From b224b859fa43fa7d3b95411870da69d3074b1398 Mon Sep 17 00:00:00 2001 From: Laura Beatris <48022589+LauraBeatris@users.noreply.github.com> Date: Tue, 21 Oct 2025 18:43:13 -0300 Subject: [PATCH 1/2] Remove deprecated `hideSlug` in favor of `organizationSettings.slug.disabled` setting --- .changeset/shiny-cats-kneel.md | 6 ++ .../CreateOrganizationForm.tsx | 8 +- .../CreateOrganizationPage.tsx | 3 +- .../__tests__/CreateOrganization.test.tsx | 100 ------------------ .../OrganizationList/OrganizationListPage.tsx | 3 +- .../__tests__/OrganizationList.test.tsx | 28 ++++- .../OrganizationSwitcherPopover.tsx | 3 +- .../__tests__/OrganizationSwitcher.test.tsx | 23 +++- .../contexts/components/CreateOrganization.ts | 1 - .../contexts/components/OrganizationList.ts | 1 - .../components/OrganizationSwitcher.ts | 1 - packages/types/src/clerk.ts | 18 ---- 12 files changed, 54 insertions(+), 141 deletions(-) create mode 100644 .changeset/shiny-cats-kneel.md diff --git a/.changeset/shiny-cats-kneel.md b/.changeset/shiny-cats-kneel.md new file mode 100644 index 00000000000..248e48d8406 --- /dev/null +++ b/.changeset/shiny-cats-kneel.md @@ -0,0 +1,6 @@ +--- +'@clerk/clerk-js': patch +'@clerk/types': patch +--- + +Remove deprecated `hideSlug` in favor of `organizationSettings.slug.disabled` setting diff --git a/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationForm.tsx b/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationForm.tsx index bed14d233f8..484c042ade2 100644 --- a/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationForm.tsx +++ b/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationForm.tsx @@ -34,12 +34,6 @@ type CreateOrganizationFormProps = { headerTitle?: LocalizationKey; headerSubtitle?: LocalizationKey; }; - /** - * @deprecated - * This prop will be removed in a future version. - * Configure whether organization slug is enabled via the Clerk Dashboard under Organization Settings. - */ - hideSlug?: boolean; }; export const CreateOrganizationForm = withCardStateProvider((props: CreateOrganizationFormProps) => { @@ -70,7 +64,7 @@ export const CreateOrganizationForm = withCardStateProvider((props: CreateOrgani const canSubmit = dataChanged; // Environment setting takes precedence over prop - const organizationSlugEnabled = !organizationSettings.slug.disabled && !props.hideSlug; + const organizationSlugEnabled = !organizationSettings.slug.disabled; const onSubmit = async (e: React.FormEvent) => { e.preventDefault(); diff --git a/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationPage.tsx b/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationPage.tsx index bb4c6e75720..a27e66ba87f 100644 --- a/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationPage.tsx +++ b/packages/clerk-js/src/ui/components/CreateOrganization/CreateOrganizationPage.tsx @@ -11,7 +11,7 @@ import { CreateOrganizationForm } from './CreateOrganizationForm'; export const CreateOrganizationPage = withCardStateProvider(() => { const { closeCreateOrganization } = useClerk(); - const { mode, navigateAfterCreateOrganization, skipInvitationScreen, hideSlug } = useCreateOrganizationContext(); + const { mode, navigateAfterCreateOrganization, skipInvitationScreen } = useCreateOrganizationContext(); const card = useCardState(); const { showDevModeNotice } = useDevMode(); @@ -33,7 +33,6 @@ export const CreateOrganizationPage = withCardStateProvider(() => { closeCreateOrganization(); } }} - hideSlug={hideSlug} /> diff --git a/packages/clerk-js/src/ui/components/CreateOrganization/__tests__/CreateOrganization.test.tsx b/packages/clerk-js/src/ui/components/CreateOrganization/__tests__/CreateOrganization.test.tsx index 4c038efb9f5..df971a00c80 100644 --- a/packages/clerk-js/src/ui/components/CreateOrganization/__tests__/CreateOrganization.test.tsx +++ b/packages/clerk-js/src/ui/components/CreateOrganization/__tests__/CreateOrganization.test.tsx @@ -80,40 +80,6 @@ describe('CreateOrganization', () => { expect(getByRole('heading', { name: 'Create organization', level: 1 })).toBeInTheDocument(); }); - describe('with `hideSlug` prop', () => { - it('renders component without slug field', async () => { - const { wrapper, fixtures, props } = await createFixtures(f => { - f.withOrganizations(); - f.withUser({ - email_addresses: ['test@clerk.com'], - }); - }); - - fixtures.clerk.createOrganization.mockReturnValue( - Promise.resolve( - getCreatedOrg({ - maxAllowedMemberships: 1, - slug: 'new-org-1722578361', - }), - ), - ); - - props.setProps({ hideSlug: true }); - const { userEvent, getByRole, queryByText, queryByLabelText, getByLabelText } = render(, { - wrapper, - }); - - expect(queryByLabelText(/Slug/i)).not.toBeInTheDocument(); - - await userEvent.type(getByLabelText(/Name/i), 'new org'); - await userEvent.click(getByRole('button', { name: /create organization/i })); - - await waitFor(() => { - expect(queryByText(/Invite new members/i)).toBeInTheDocument(); - }); - }); - }); - describe('with organization slug configured on environment', () => { it('when disabled, renders component without slug field', async () => { const { wrapper, fixtures } = await createFixtures(f => { @@ -178,72 +144,6 @@ describe('CreateOrganization', () => { expect(queryByText(/Invite new members/i)).toBeInTheDocument(); }); }); - - it('when enabled and `hideSlug` prop is passed, renders component without slug field', async () => { - const { wrapper, fixtures, props } = await createFixtures(f => { - f.withOrganizations(); - f.withOrganizationSlug(true); - f.withUser({ - email_addresses: ['test@clerk.com'], - }); - }); - - fixtures.clerk.createOrganization.mockReturnValue( - Promise.resolve( - getCreatedOrg({ - maxAllowedMemberships: 1, - slug: 'new-org-1722578361', - }), - ), - ); - - props.setProps({ hideSlug: true }); - const { userEvent, getByRole, queryByText, queryByLabelText, getByLabelText } = render(, { - wrapper, - }); - - expect(queryByLabelText(/Slug/i)).not.toBeInTheDocument(); - - await userEvent.type(getByLabelText(/Name/i), 'new org'); - await userEvent.click(getByRole('button', { name: /create organization/i })); - - await waitFor(() => { - expect(queryByText(/Invite new members/i)).toBeInTheDocument(); - }); - }); - - it('when disabled and `hideSlug` prop is passed, renders component without slug field', async () => { - const { wrapper, fixtures, props } = await createFixtures(f => { - f.withOrganizations(); - f.withOrganizationSlug(false); // Environment disables slug - f.withUser({ - email_addresses: ['test@clerk.com'], - }); - }); - - fixtures.clerk.createOrganization.mockReturnValue( - Promise.resolve( - getCreatedOrg({ - maxAllowedMemberships: 1, - slug: 'new-org-1722578361', - }), - ), - ); - - props.setProps({ hideSlug: true }); - const { userEvent, getByRole, queryByText, queryByLabelText, getByLabelText } = render(, { - wrapper, - }); - - expect(queryByLabelText(/Slug/i)).not.toBeInTheDocument(); - - await userEvent.type(getByLabelText(/Name/i), 'new org'); - await userEvent.click(getByRole('button', { name: /create organization/i })); - - await waitFor(() => { - expect(queryByText(/Invite new members/i)).toBeInTheDocument(); - }); - }); }); it('skips invitation screen', async () => { diff --git a/packages/clerk-js/src/ui/components/OrganizationList/OrganizationListPage.tsx b/packages/clerk-js/src/ui/components/OrganizationList/OrganizationListPage.tsx index 0d7327fe13c..dca8ee06b36 100644 --- a/packages/clerk-js/src/ui/components/OrganizationList/OrganizationListPage.tsx +++ b/packages/clerk-js/src/ui/components/OrganizationList/OrganizationListPage.tsx @@ -85,7 +85,7 @@ export const OrganizationListPage = withCardStateProvider(() => { const OrganizationListFlows = ({ showListInitially }: { showListInitially: boolean }) => { const card = useCardState(); - const { navigateAfterCreateOrganization, skipInvitationScreen, hideSlug } = useOrganizationListContext(); + const { navigateAfterCreateOrganization, skipInvitationScreen } = useOrganizationListContext(); const [isCreateOrganizationFlow, setCreateOrganizationFlow] = useState(!showListInitially); return ( <> @@ -112,7 +112,6 @@ const OrganizationListFlows = ({ showListInitially }: { showListInitially: boole onCancel={ showListInitially && isCreateOrganizationFlow ? () => setCreateOrganizationFlow(false) : undefined } - hideSlug={hideSlug} /> diff --git a/packages/clerk-js/src/ui/components/OrganizationList/__tests__/OrganizationList.test.tsx b/packages/clerk-js/src/ui/components/OrganizationList/__tests__/OrganizationList.test.tsx index 09ad363316b..c343a72658c 100644 --- a/packages/clerk-js/src/ui/components/OrganizationList/__tests__/OrganizationList.test.tsx +++ b/packages/clerk-js/src/ui/components/OrganizationList/__tests__/OrganizationList.test.tsx @@ -3,12 +3,12 @@ import { describe, expect, it, vi } from 'vitest'; import { bindCreateFixtures } from '@/test/create-fixtures'; import { render, waitFor } from '@/test/utils'; +import { OrganizationList } from '../'; import { createFakeOrganization } from '../../CreateOrganization/__tests__/CreateOrganization.test'; import { createFakeUserOrganizationInvitation, createFakeUserOrganizationMembership, } from '../../OrganizationSwitcher/__tests__/test-utils'; -import { OrganizationList } from '../'; const { createFixtures } = bindCreateFixtures('OrganizationList'); @@ -277,16 +277,16 @@ describe('OrganizationList', () => { }); }); - it('displays CreateOrganization without slug field', async () => { - const { wrapper, props } = await createFixtures(f => { + it("does not display slug field if it's disabled on environment", async () => { + const { wrapper } = await createFixtures(f => { f.withOrganizations(); + f.withOrganizationSlug(false); f.withUser({ email_addresses: ['test@clerk.com'], create_organization_enabled: true, }); }); - props.setProps({ hideSlug: true }); const { findByRole, getByRole, userEvent, queryByLabelText } = render(, { wrapper }); await waitFor(async () => @@ -297,6 +297,26 @@ describe('OrganizationList', () => { expect(queryByLabelText(/Slug/i)).not.toBeInTheDocument(); }); + it("display slug field if it's enabled on environment", async () => { + const { wrapper } = await createFixtures(f => { + f.withOrganizations(); + f.withOrganizationSlug(true); + f.withUser({ + email_addresses: ['test@clerk.com'], + create_organization_enabled: true, + }); + }); + + const { findByRole, getByRole, userEvent, queryByLabelText } = render(, { wrapper }); + + await waitFor(async () => + expect(await findByRole('menuitem', { name: 'Create organization' })).toBeInTheDocument(), + ); + await userEvent.click(getByRole('menuitem', { name: 'Create organization' })); + expect(queryByLabelText(/Name/i)).toBeInTheDocument(); + expect(queryByLabelText(/Slug/i)).toBeInTheDocument(); + }); + it('does not display CreateOrganization within OrganizationList when disabled', async () => { const { wrapper } = await createFixtures(f => { f.withOrganizations(); diff --git a/packages/clerk-js/src/ui/components/OrganizationSwitcher/OrganizationSwitcherPopover.tsx b/packages/clerk-js/src/ui/components/OrganizationSwitcher/OrganizationSwitcherPopover.tsx index 10e5df31ca7..4e3dcca64f4 100644 --- a/packages/clerk-js/src/ui/components/OrganizationSwitcher/OrganizationSwitcherPopover.tsx +++ b/packages/clerk-js/src/ui/components/OrganizationSwitcher/OrganizationSwitcherPopover.tsx @@ -49,7 +49,6 @@ export const OrganizationSwitcherPopover = React.forwardRef { diff --git a/packages/clerk-js/src/ui/components/OrganizationSwitcher/__tests__/OrganizationSwitcher.test.tsx b/packages/clerk-js/src/ui/components/OrganizationSwitcher/__tests__/OrganizationSwitcher.test.tsx index c854f15f702..77ea1ad9b59 100644 --- a/packages/clerk-js/src/ui/components/OrganizationSwitcher/__tests__/OrganizationSwitcher.test.tsx +++ b/packages/clerk-js/src/ui/components/OrganizationSwitcher/__tests__/OrganizationSwitcher.test.tsx @@ -253,16 +253,16 @@ describe('OrganizationSwitcher', () => { expect(fixtures.clerk.openCreateOrganization).toHaveBeenCalled(); }); - it('opens create organization without slug field', async () => { - const { wrapper, fixtures, props } = await createFixtures(f => { + it("does not display slug field if it's disabled on environment", async () => { + const { wrapper, fixtures } = await createFixtures(f => { f.withOrganizations(); + f.withOrganizationSlug(false); f.withUser({ email_addresses: ['test@clerk.com'], create_organization_enabled: true, }); }); - props.setProps({ hideSlug: true }); const { getByRole, queryByLabelText, userEvent } = render(, { wrapper }); await userEvent.click(getByRole('button', { name: 'Open organization switcher' })); await userEvent.click(getByRole('menuitem', { name: 'Create organization' })); @@ -270,6 +270,23 @@ describe('OrganizationSwitcher', () => { expect(queryByLabelText(/Slug/i)).not.toBeInTheDocument(); }); + it("display slug field if it's enabled on environment", async () => { + const { wrapper, fixtures } = await createFixtures(f => { + f.withOrganizations(); + f.withOrganizationSlug(true); + f.withUser({ + email_addresses: ['test@clerk.com'], + create_organization_enabled: true, + }); + }); + + const { getByRole, queryByLabelText, userEvent } = render(, { wrapper }); + await userEvent.click(getByRole('button', { name: 'Open organization switcher' })); + await userEvent.click(getByRole('menuitem', { name: 'Create organization' })); + expect(fixtures.clerk.openCreateOrganization).toHaveBeenCalled(); + expect(queryByLabelText(/Slug/i)).toBeInTheDocument(); + }); + it('does not display create organization button if permissions not present', async () => { const { wrapper, props } = await createFixtures(f => { f.withOrganizations(); diff --git a/packages/clerk-js/src/ui/contexts/components/CreateOrganization.ts b/packages/clerk-js/src/ui/contexts/components/CreateOrganization.ts index 32d4f13c69f..2ed14e694ab 100644 --- a/packages/clerk-js/src/ui/contexts/components/CreateOrganization.ts +++ b/packages/clerk-js/src/ui/contexts/components/CreateOrganization.ts @@ -38,7 +38,6 @@ export const useCreateOrganizationContext = () => { return { ...ctx, skipInvitationScreen: ctx.skipInvitationScreen || false, - hideSlug: ctx.hideSlug || false, navigateAfterCreateOrganization, componentName, }; diff --git a/packages/clerk-js/src/ui/contexts/components/OrganizationList.ts b/packages/clerk-js/src/ui/contexts/components/OrganizationList.ts index 0c07c4161f4..cb9f4938813 100644 --- a/packages/clerk-js/src/ui/contexts/components/OrganizationList.ts +++ b/packages/clerk-js/src/ui/contexts/components/OrganizationList.ts @@ -79,7 +79,6 @@ export const useOrganizationListContext = () => { ...ctx, afterCreateOrganizationUrl, skipInvitationScreen: ctx.skipInvitationScreen || false, - hideSlug: ctx.hideSlug || false, hidePersonal: organizationSettings.forceOrganizationSelection || ctx.hidePersonal || false, navigateAfterCreateOrganization, navigateAfterSelectOrganization, diff --git a/packages/clerk-js/src/ui/contexts/components/OrganizationSwitcher.ts b/packages/clerk-js/src/ui/contexts/components/OrganizationSwitcher.ts index b4afacd7bd5..c23ba2966fd 100644 --- a/packages/clerk-js/src/ui/contexts/components/OrganizationSwitcher.ts +++ b/packages/clerk-js/src/ui/contexts/components/OrganizationSwitcher.ts @@ -100,7 +100,6 @@ export const useOrganizationSwitcherContext = () => { organizationProfileMode: organizationProfileMode || 'modal', createOrganizationMode: createOrganizationMode || 'modal', skipInvitationScreen: ctx.skipInvitationScreen || false, - hideSlug: ctx.hideSlug || false, afterCreateOrganizationUrl, afterLeaveOrganizationUrl, navigateOrganizationProfile, diff --git a/packages/types/src/clerk.ts b/packages/types/src/clerk.ts index a8fc6103bc9..52843ecc212 100644 --- a/packages/types/src/clerk.ts +++ b/packages/types/src/clerk.ts @@ -1562,12 +1562,6 @@ export type CreateOrganizationProps = RoutingOptions & { * prop of ClerkProvider (if one is provided) */ appearance?: CreateOrganizationTheme; - /** - * @deprecated - * This prop will be removed in a future version. - * Configure whether organization slug is enabled via the Clerk Dashboard under Organization Settings. - */ - hideSlug?: boolean; }; export type CreateOrganizationModalProps = WithoutRouting; @@ -1723,12 +1717,6 @@ export type OrganizationSwitcherProps = CreateOrganizationMode & * the number of max allowed members is equal to 1 */ skipInvitationScreen?: boolean; - /** - * @deprecated - * This prop will be removed in a future version. - * Configure whether organization slug is enabled via the Clerk Dashboard under Organization Settings. - */ - hideSlug?: boolean; /** * Customisation options to fully match the Clerk components to your own brand. * These options serve as overrides and will be merged with the global `appearance` @@ -1784,12 +1772,6 @@ export type OrganizationListProps = { * @default undefined` */ afterSelectPersonalUrl?: ((user: UserResource) => string) | LooseExtractedParams>; - /** - * @deprecated - * This prop will be removed in a future version. - * Configure whether organization slug is enabled via the Clerk Dashboard under Organization Settings. - */ - hideSlug?: boolean; }; export type WaitlistProps = { From 2ff8f96d372bdb60b6e8ab519243f1f1c88ada31 Mon Sep 17 00:00:00 2001 From: Laura Beatris <48022589+LauraBeatris@users.noreply.github.com> Date: Wed, 22 Oct 2025 14:08:32 -0300 Subject: [PATCH 2/2] Remove unit tests within OrgSwitcher Those assertions should stay within the CreateOrganization spec, sincethe modal cannot be opened within this test suite --- .../__tests__/OrganizationList.test.tsx | 2 +- .../__tests__/OrganizationSwitcher.test.tsx | 34 ------------------- 2 files changed, 1 insertion(+), 35 deletions(-) diff --git a/packages/clerk-js/src/ui/components/OrganizationList/__tests__/OrganizationList.test.tsx b/packages/clerk-js/src/ui/components/OrganizationList/__tests__/OrganizationList.test.tsx index c343a72658c..2a44d32acdf 100644 --- a/packages/clerk-js/src/ui/components/OrganizationList/__tests__/OrganizationList.test.tsx +++ b/packages/clerk-js/src/ui/components/OrganizationList/__tests__/OrganizationList.test.tsx @@ -3,12 +3,12 @@ import { describe, expect, it, vi } from 'vitest'; import { bindCreateFixtures } from '@/test/create-fixtures'; import { render, waitFor } from '@/test/utils'; -import { OrganizationList } from '../'; import { createFakeOrganization } from '../../CreateOrganization/__tests__/CreateOrganization.test'; import { createFakeUserOrganizationInvitation, createFakeUserOrganizationMembership, } from '../../OrganizationSwitcher/__tests__/test-utils'; +import { OrganizationList } from '../'; const { createFixtures } = bindCreateFixtures('OrganizationList'); diff --git a/packages/clerk-js/src/ui/components/OrganizationSwitcher/__tests__/OrganizationSwitcher.test.tsx b/packages/clerk-js/src/ui/components/OrganizationSwitcher/__tests__/OrganizationSwitcher.test.tsx index 77ea1ad9b59..f1d607166c0 100644 --- a/packages/clerk-js/src/ui/components/OrganizationSwitcher/__tests__/OrganizationSwitcher.test.tsx +++ b/packages/clerk-js/src/ui/components/OrganizationSwitcher/__tests__/OrganizationSwitcher.test.tsx @@ -253,40 +253,6 @@ describe('OrganizationSwitcher', () => { expect(fixtures.clerk.openCreateOrganization).toHaveBeenCalled(); }); - it("does not display slug field if it's disabled on environment", async () => { - const { wrapper, fixtures } = await createFixtures(f => { - f.withOrganizations(); - f.withOrganizationSlug(false); - f.withUser({ - email_addresses: ['test@clerk.com'], - create_organization_enabled: true, - }); - }); - - const { getByRole, queryByLabelText, userEvent } = render(, { wrapper }); - await userEvent.click(getByRole('button', { name: 'Open organization switcher' })); - await userEvent.click(getByRole('menuitem', { name: 'Create organization' })); - expect(fixtures.clerk.openCreateOrganization).toHaveBeenCalled(); - expect(queryByLabelText(/Slug/i)).not.toBeInTheDocument(); - }); - - it("display slug field if it's enabled on environment", async () => { - const { wrapper, fixtures } = await createFixtures(f => { - f.withOrganizations(); - f.withOrganizationSlug(true); - f.withUser({ - email_addresses: ['test@clerk.com'], - create_organization_enabled: true, - }); - }); - - const { getByRole, queryByLabelText, userEvent } = render(, { wrapper }); - await userEvent.click(getByRole('button', { name: 'Open organization switcher' })); - await userEvent.click(getByRole('menuitem', { name: 'Create organization' })); - expect(fixtures.clerk.openCreateOrganization).toHaveBeenCalled(); - expect(queryByLabelText(/Slug/i)).toBeInTheDocument(); - }); - it('does not display create organization button if permissions not present', async () => { const { wrapper, props } = await createFixtures(f => { f.withOrganizations();