diff --git a/docs/components/customization/organization-profile.mdx b/docs/components/customization/organization-profile.mdx new file mode 100644 index 0000000000..d2959b5d99 --- /dev/null +++ b/docs/components/customization/organization-profile.mdx @@ -0,0 +1,416 @@ +--- +title: customization +description: Learn how to add custom pages and include external links within the navigation sidebar of the component. +--- + +# `` customization + +The [``][orgprofile-ref] component supports the addition of custom pages and use of external links in the navigation sidebar. + +## `` + +Custom pages can be rendered inside the [``][orgprofile-ref] component and provide a way to incorporate app-specific settings or additional functionality. + +To add a custom page to the [``][orgprofile-ref] component, use the `` component. + +### Usage + + + + `` can be rendered **only on the client**. For Next.js applications using App Router, the `"use client";` directive must be added. + + + ```jsx filename="/app/organization-profile/[[...organization-profile]]/page.tsx" + "use client"; + + import { OrganizationProfile } from "@clerk/nextjs"; + import { CustomProfilePage, CustomTerms } from "../components"; + import { CustomIcon } from "../icons"; + + const OrganizationProfilePage = () => ( + + } url="custom-page"> + + + } url="terms"> + + + + ); + + export default OrganizationProfilePage; + ``` + + ```jsx filename="/pages/organization-profile/[[...index]].tsx" + import { OrganizationProfile } from "@clerk/nextjs"; + import { CustomProfilePage, CustomTerms } from "../components"; + import { CustomIcon } from "../icons"; + + const OrganizationProfilePage = () => ( + + } url="custom-page"> + + + } url="terms"> + + + + ); + + export default OrganizationProfilePage; + ``` + + + + + ```jsx filename="/organization-profile.tsx" + import { OrganizationProfile } from "@clerk/clerk-react"; + import { CustomProfilePage, CustomTerms } from "../components"; + import { CustomIcon } from "../icons"; + + const OrganizationProfilePage = () => ( + + } url="custom-page"> + + + } url="terms"> + + + + ); + + export default OrganizationProfilePage; + ``` + + + + ```tsx filename="routes/organization/$.tsx" + import { OrganizationProfile } from "@clerk/remix"; + import { CustomProfilePage, CustomTerms } from "../components"; + import { CustomIcon } from "../icons"; + + export default function OrganizationProfilePage() { + return ( + + } url="custom-page"> + + + } url="terms"> + + + + ); + } + ``` + + + +### Props + +All props below are required. + +| Name | Type | Description | +| --- | --- | --- | +| `label` | `string` | The name that will be displayed in the navigation sidebar for the custom page. | +| `labelIcon` | `React.ReactElement` | An icon displayed next to the label in the navigation sidebar. | +| `url` | `string` | The path segment that will be used to navigate to the custom page. (e.g. if the `OrganizationProfile` component is rendered at `/organization`, then the custom page will be accessed at `/organization/{url}` when using path routing). | +| `children` | `React.ReactElement` | The components to be rendered as content inside the custom page. | + +## `` + +You can add external links to the [``][orgprofile-ref] navigation sidebar using the `` component. + +### Usage + + + + `` can be rendered **only on the client**. For Next.js applications using App Router, the `"use client";` directive must be added. + + + ```jsx filename="/app/organization-profile/[[...organization-profile]]/page.tsx" + "use client"; + + import { OrganizationProfile } from "@clerk/nextjs"; + import { CustomIcon } from "../icons"; + + const OrganizationProfilePage = () => ( + + } url="/home" /> + + ); + + export default OrganizationProfilePage; + ``` + + ```jsx filename="/pages/organization-profile/[[...index]].tsx" + import { OrganizationProfile } from "@clerk/nextjs"; + import { CustomIcon } from "../icons"; + + const OrganizationProfilePage = () => ( + + } url="/home" /> + + ); + + export default OrganizationProfilePage; + ``` + + + + + ```jsx filename="/organization-profile.tsx" + import { OrganizationProfile } from "@clerk/clerk-react"; + import { CustomIcon } from "../icons"; + + const OrganizationProfilePage = () => ( + + } url="/home" /> + + ); + + export default OrganizationProfilePage; + ``` + + + + ```tsx filename="routes/organization/$.tsx" + import { OrganizationProfile } from "@clerk/remix"; + import { CustomIcon } from "../icons"; + + export default function OrganizationProfilePage() { + return ( + + } url="/home" /> + + ); + } + ``` + + + + +### Props + +All props below are required. + +| Name | Type | Description | +| --- | --- | --- | +| `label` | `string` | The name that will be displayed in the navigation sidebar for the link. | +| `labelIcon` | `React.ReactElement` | An icon displayed next to the label in the navigation sidebar. | +| `url` | `string` | The absolute or relative url to navigate to. | + + +## Advanced use cases + +### Reordering default routes + +If you want to reorder the default routes (`Members` and `Settings`) in the `OrganizationProfile` navigation sidebar, you can use the `` component with the `label` prop set to `'members'` or `'settings'`. This will target the existing default page and allow you to rearrange it. + +### Usage + + + + `` and `` can be rendered **only on the client**. For Next.js applications that use App Router, the `"use client";` directive needs to be used. + + + ```jsx filename="/app/organization-profile/[[...organization-profile]]/page.tsx" + "use client"; + + import { OrganizationProfile } from "@clerk/nextjs"; + import { MyCustomPageContent } from "../components"; + import { CustomIcon, Icon } from "../icons"; + + const OrganizationProfilePage = () => ( + + }> + + + } /> + + + + ); + + export default OrganizationProfilePage; + ``` + + ```jsx filename="/pages/organization-profile/[[...index]].tsx" + import { OrganizationProfile } from "@clerk/nextjs"; + import { MyCustomPageContent } from "../components"; + import { CustomIcon, Icon } from "../icons"; + + const OrganizationProfilePage = () => ( + + }> + + + } /> + + + + ); + + export default OrganizationProfilePage; + ``` + + + + + ```jsx filename="/organization-profile.tsx" + import { OrganizationProfile } from "@clerk/clerk-react"; + import { MyCustomPageContent } from "../components"; + import { CustomIcon, Icon } from "../icons"; + + const OrganizationProfilePage = () => ( + + }> + + + } /> + + + + ); + + export default OrganizationProfilePage; + ``` + + + + ```tsx filename="routes/organization/$.tsx" + import { OrganizationProfile } from "@clerk/remix"; + import { MyCustomPageContent } from "../components"; + import { CustomIcon, Icon } from "../icons"; + + export default function OrganizationProfilePage() { + return ( + + }> + + + } /> + + + + ); + } + ``` + + + +The above example will result in the following order: + +1. Custom Page +2. Homepage +3. Members +4. Settings + +It's important to note that the first page in the list will be rendered under the root path `/` (its `url` will be ignored) and the Clerk pages will be rendered under the path `/organitzation-members` and `/organization-settings`. Also, the first item in the list cannot be a `` component. + +### Using custom pages with the `` component + +If you are using the `` component with the default props (where the `OrganizationProfile` opens as a modal), then you should also be providing these custom pages as children to the component (using the `` and `` components respectively). + +### Usage + + + + `` and `` can be rendered **only on the client**. For Next.js applications using App Router, the `"use client";` directive must be added. + + + ```jsx filename="/app/components/Header.tsx" + "use client"; + + import { OrganizationSwitcher } from "@clerk/nextjs"; + import { MyCustomPageContent } from "../components"; + import { CustomIcon, Icon } from "../icons"; + + const Header = () => ( +
+ + }> + + + } /> + + + +
+ ); + + export default Header; + ``` + + ```jsx filename="/pages/components/Header.tsx" + import { OrganizationSwitcher } from "@clerk/nextjs"; + import { MyCustomPageContent } from "../components"; + import { CustomIcon, Icon } from "../icons"; + + const Header = () => ( +
+ + }> + + + } /> + + + +
+ ); + + export default Header; + ``` +
+
+ + + ```jsx filename="/components/Header.tsx" + import { OrganizationSwitcher } from "@clerk/clerk-react"; + import { MyCustomPageContent } from "../components"; + import { CustomIcon, Icon } from "../icons"; + + const Header = () => ( +
+ + }> + + + } /> + + + +
+ ); + + export default Header; + ``` +
+ + + ```tsx filename="components/Header.tsx" + import { OrganizationSwitcher } from "@clerk/remix"; + import { MyCustomPageContent } from "../components"; + import { CustomIcon, Icon } from "../icons"; + + export default function Header() { + return ( +
+ + }> + + + } /> + + + +
+ ); + } + ``` +
+
+ +This repetition of the same property can be avoided when the user is using the `organizationProfileMode='navigation'` and `organizationProfileUrl=''` props on the `` component and has implemented a dedicated page for the [``][orgprofile-ref] component. + +[orgprofile-ref]: /docs/components/organization/organization-profile \ No newline at end of file diff --git a/docs/components/customization/user-profile.mdx b/docs/components/customization/user-profile.mdx new file mode 100644 index 0000000000..3ee21dc0b1 --- /dev/null +++ b/docs/components/customization/user-profile.mdx @@ -0,0 +1,416 @@ +--- +title: customization +description: Learn how to add custom pages and include external links within the navigation sidebar of the component. +--- + +# `` customization + +The [``][userprofile-ref] component supports the addition of custom pages and use of external links in the navigation sidebar. + +## `` + +Custom pages can be rendered inside the [``][userprofile-ref] component and provide a way to incorporate app-specific settings or additional functionality. + +To add a custom page to the [``][userprofile-ref] component, use the `` component. + +### Usage + + + + `` can be rendered **only on the client**. For Next.js applications using App Router, the `"use client";` directive must be added. + + + ```jsx filename="/app/user-profile/[[...user-profile]]/page.tsx" + "use client"; + + import { UserProfile } from "@clerk/nextjs"; + import { CustomProfilePage, CustomTerms } from "../components"; + import { CustomIcon } from "../icons"; + + const UserProfilePage = () => ( + + } url="custom-page"> + + + } url="terms"> + + + + ); + + export default UserProfilePage; + ``` + + ```jsx filename="/pages/user-profile/[[...index]].tsx" + import { UserProfile } from "@clerk/nextjs"; + import { CustomProfilePage, CustomTerms } from "../components"; + import { CustomIcon } from "../icons"; + + const UserProfilePage = () => ( + + } url="custom-page"> + + + } url="terms"> + + + + ); + + export default UserProfilePage; + ``` + + + + + ```jsx filename="/user-profile.tsx" + import { UserProfile } from "@clerk/clerk-react"; + import { CustomProfilePage, CustomTerms } from "../components"; + import { CustomIcon } from "../icons"; + + const UserProfilePage = () => ( + + } url="custom-page"> + + + } url="terms"> + + + + ); + + export default UserProfilePage; + ``` + + + + ```tsx filename="routes/user/$.tsx" + import { UserProfile } from "@clerk/remix"; + import { CustomProfilePage, CustomTerms } from "../components"; + import { CustomIcon } from "../icons"; + + export default function UserProfilePage() { + return ( + + } url="custom-page"> + + + } url="terms"> + + + + ); + } + ``` + + + +### Props + +All props below are required. + +| Name | Type | Description | +| --- | --- | --- | +| `label` | `string` | The name that will be displayed in the navigation sidebar for the custom page. | +| `labelIcon` | `React.ReactElement` | An icon displayed next to the label in the navigation sidebar. | +| `url` | `string` | The path segment that will be used to navigate to the custom page. (e.g. if the `UserProfile` component is rendered at `/user`, then the custom page will be accessed at `/user/{url}` when using path routing) | +| `children` | `React.ReactElement` | The components to be rendered as content inside the custom page. | + +## `` + +You can add external links to the [``][userprofile-ref] navigation sidebar using the `` component. + +### Usage + + + + `` can be rendered **only on the client**. For Next.js applications using App Router, the `"use client";` directive must be added. + + + ```jsx filename="/app/user-profile/[[...user-profile]]/page.tsx" + "use client"; + + import { UserProfile } from "@clerk/nextjs"; + import { CustomIcon } from "../icons"; + + const UserProfilePage = () => ( + + } url="/home" /> + + ); + + export default UserProfilePage; + ``` + + ```jsx filename="/pages/user-profile/[[...index]].tsx" + import { UserProfile } from "@clerk/nextjs"; + import { CustomIcon } from "../icons"; + + const UserProfilePage = () => ( + + } url="/home" /> + + ); + + export default UserProfilePage; + ``` + + + + + ```jsx filename="/user-profile.tsx" + import { UserProfile } from "@clerk/clerk-react"; + import { CustomIcon } from "../icons"; + + const UserProfilePage = () => ( + + } url="/home" /> + + ); + + export default UserProfilePage; + ``` + + + + ```tsx filename="routes/user/$.tsx" + import { UserProfile } from "@clerk/remix"; + import { CustomIcon } from "../icons"; + + export default function UserProfilePage() { + return ( + + } url="/home" /> + + ); + } + ``` + + + + +### Props + +All props below are required. + +| Name | Type | Description | +| --- | --- | --- | +| `label` | `string` | The name that will be displayed in the navigation sidebar for the link. | +| `labelIcon` | `React.ReactElement` | An icon displayed next to the label in the navigation sidebar. | +| `url` | `string` | The absolute or relative url to navigate to | + + +## Advanced use cases + +### Reordering Default Routes + +If you want to reorder the default routes (`Account` and `Security`) in the `UserProfile` navigation sidebar, you can use the `` component with the `label` prop set to `'account'` or `'security'`. This will target the existing default page and allow you to rearrange it. + +### Usage + + + + `` and `` can be rendered **only on the client**. For Next.js applications using App Router, the `"use client";` directive must be added. + + + ```jsx filename="/app/user-profile/[[...user-profile]]/page.tsx" + "use client"; + + import { UserProfile } from "@clerk/nextjs"; + import { MyCustomPageContent } from "../components"; + import { CustomIcon, Icon } from "../icons"; + + const UserProfilePage = () => ( + + }> + + + } /> + + + + ); + + export default UserProfilePage; + ``` + + ```jsx filename="/pages/user-profile/[[...index]].tsx" + import { UserProfile } from "@clerk/nextjs"; + import { MyCustomPageContent } from "../components"; + import { CustomIcon, Icon } from "../icons"; + + const UserProfilePage = () => ( + + }> + + + } /> + + + + ); + + export default UserProfilePage; + ``` + + + + + ```jsx filename="/user-profile.tsx" + import { UserProfile } from "@clerk/clerk-react"; + import { MyCustomPageContent } from "../components"; + import { CustomIcon, Icon } from "../icons"; + + const UserProfilePage = () => ( + + }> + + + } /> + + + + ); + + export default UserProfilePage; + ``` + + + + ```tsx filename="routes/user/$.tsx" + import { UserProfile } from "@clerk/remix"; + import { MyCustomPageContent } from "../components"; + import { CustomIcon, Icon } from "../icons"; + + export default function UserProfilePage() { + return ( + + }> + + + } /> + + + + ); + } + ``` + + + +The above example will result in the following order: + +1. Custom Page +2. Homepage +3. Account +4. Security + +It's important to note that the first page in the list will be rendered under the root path `/` (its `url` will be ignored) and the Clerk pages will be rendered under the path `/account`. Also, the first item in the list cannot be a `` component. + +### Using custom pages with the `` component + +If you are using the `` component with the default props (where the `UserProfile` opens as a modal), then you should also be providing these custom pages as children to the component (using the `` and `` components respectively). + +### Usage + + + + `` and `` can be rendered **only on the client**. For Next.js applications using App Router, the `"use client";` directive must be added. + + + ```jsx filename="/app/components/Header.tsx" + "use client"; + + import { UserButton } from "@clerk/nextjs"; + import { MyCustomPageContent } from "../components"; + import { CustomIcon, Icon } from "../icons"; + + const Header = () => ( +
+ + }> + + + } /> + + + +
+ ); + + export default Header; + ``` + + ```jsx filename="/pages/components/Header.tsx" + import { UserButton } from "@clerk/nextjs"; + import { MyCustomPageContent } from "../components"; + import { CustomIcon, Icon } from "../icons"; + + const Header = () => ( +
+ + }> + + + } /> + + + +
+ ); + + export default Header; + ``` +
+
+ + + ```jsx filename="/components/Header.tsx" + import { UserButton } from "@clerk/clerk-react"; + import { MyCustomPageContent } from "../components"; + import { CustomIcon, Icon } from "../icons"; + + const Header = () => ( +
+ + }> + + + } /> + + + +
+ ); + + export default Header; + ``` +
+ + + ```tsx filename="components/Header.tsx" + import { UserButton } from "@clerk/remix"; + import { MyCustomPageContent } from "../components"; + import { CustomIcon, Icon } from "../icons"; + + export default function Header() { + return ( +
+ + }> + + + } /> + + + +
+ ); + } + ``` +
+
+ +This repetition of the same property can be avoided when the user is using the `userProfileMode='navigation'` and `userProfileUrl=''` props on the `` component and has implemented a dedicated page for the [``][userprofile-ref] component. + +[userprofile-ref]: /docs/components/user/user-profile \ No newline at end of file diff --git a/docs/manifest.json b/docs/manifest.json index 7aa22a44d5..142e298dfd 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -216,6 +216,13 @@ ] ], ["Localization prop (i18n)", "/components/customization/localization"], + [ + { "title": "Custom Pages" }, + [ + ["", "/components/customization/user-profile"], + ["", "/components/customization/organization-profile"] + ] + ], "# Control Components", [ "", @@ -580,7 +587,8 @@ ["DeletedObject", "/references/javascript/types/deleted-object"], ["OAuthProvider", "/references/javascript/types/oauth-provider"], ["OAuthStrategy", "/references/javascript/types/oauth-strategy"], - ["PaginatedResponse", "/references/javascript/types/paginated-response"] + ["PaginatedResponse", "/references/javascript/types/paginated-response"], + ["CustomPage", "/references/javascript/types/custom-page"] ] ] ] diff --git a/docs/references/javascript/clerk/organization-profile.mdx b/docs/references/javascript/clerk/organization-profile.mdx index 8ee06672e6..cf7dd3f0c4 100644 --- a/docs/references/javascript/clerk/organization-profile.mdx +++ b/docs/references/javascript/clerk/organization-profile.mdx @@ -236,6 +236,103 @@ Closes the organization profile overlay. function closeOrganizationProfile(): void; ``` +## Custom Pages + +You can add customized pages for the [``][orgprofile-ref] component by using the `customPages` prop. + + + + ```typescript {11} + import Clerk from '@clerk/clerk-js'; + + const clerk = new Clerk('pk_[publishable_key]'); + await clerk.load(); + + clerk.openOrganizationProfile({ + customPages: [ + { + url: "custom-page", + label: "Custom Page", + mountIcon: (el) => { + el.innerHTML = "👋"; + }, + unmountIcon: (el) => { + el.innerHTML = ""; + }, + mount: (el) => { + el.innerHTML = ` +

Custom Page

+

This is the content of the custom page.

+ `; + }, + unmount: (el) => { + el.innerHTML = ""; + }, + }, + { + url: "/other-page", + label: "Other Page", + mountIcon: (el) => { + el.innerHTML = "🌐"; + }, + unmountIcon: (el) => { + el.innerHTML = ""; + }, + } + ] + }); + + ``` + + ```html {14} + + ``` +
+ ## `OrganizationProfileProps` All props below are optional. @@ -246,7 +343,10 @@ All props below are optional. | `routing` | `'hash' \| 'path' \| 'virtual'` | The routing strategy for your pages. | | `path` | `string` | The path where the component is mounted when path-based routing is used.
e.g. `/user-profile`.
This prop is ignored in hash-based routing. | | `appearance` | [Appearance](/docs/components/customization/overview) \| undefined | Optional object to style your components. Will only affect [Clerk Components][components-ref] and not [Account Portal][ap-ref] pages. | +| `customPages` | [CustomPage][custompage-ref][] | An array of custom pages to add to the organization profile. | + [orgprofile-ref]: /docs/components/organization/organization-profile [components-ref]: /docs/components/overview -[ap-ref]: /docs/account-portal/overview \ No newline at end of file +[ap-ref]: /docs/account-portal/overview +[custompage-ref]: /docs/references/javascript/types/custom-page diff --git a/docs/references/javascript/clerk/user-profile.mdx b/docs/references/javascript/clerk/user-profile.mdx index 91e0bd6f9f..21bccfd70c 100644 --- a/docs/references/javascript/clerk/user-profile.mdx +++ b/docs/references/javascript/clerk/user-profile.mdx @@ -236,6 +236,103 @@ Closes the user profile overlay. function closeUserProfile(): void; ``` +## Custom Pages + +You can add customized pages for the [``][userprofile-ref] component by using the `customPages` prop. + + + ```typescript {11} + import Clerk from '@clerk/clerk-js'; + + const clerk = new Clerk('pk_[publishable_key]'); + await clerk.load(); + + clerk.openUserProfile({ + customPages: [ + { + url: "custom-page", + label: "Custom Page", + mountIcon: (el) => { + el.innerHTML = "👋"; + }, + unmountIcon: (el) => { + el.innerHTML = ""; + }, + mount: (el) => { + el.innerHTML = ` +

Custom Page

+

This is the content of the custom page.

+ `; + }, + unmount: (el) => { + el.innerHTML = ""; + }, + }, + { + url: "/other-page", + label: "Other Page", + mountIcon: (el) => { + el.innerHTML = "🌐"; + }, + unmountIcon: (el) => { + el.innerHTML = ""; + }, + } + ] + }); + + ``` + + ```html {14} + + ``` +
+ ## `UserProfileProps` All props below are optional. @@ -246,7 +343,10 @@ All props below are optional. | `routing` | `'hash' \| 'path' \| 'virtual'` | The routing strategy for your pages. | | `path` | `string` | The path where the component is mounted when path-based routing is used.
e.g. `/user-profile`.
This prop is ignored in hash-based routing. | | `additionalOAuthScopes` | `object` | Specify additional scopes per OAuth provider that your users would like to provide if not already approved.
e.g. `{google: ['foo', 'bar'], github: ['qux']}` | +| `customPages` | [CustomPage][custompage-ref]\[\] | An array of custom pages to add to the user profile. | [userprofile-ref]: /docs/components/user/user-profile [components-ref]: /docs/components/overview [ap-ref]: /docs/account-portal/overview +[custompage-ref]: /docs/references/javascript/types/custom-page + diff --git a/docs/references/javascript/types/custom-page.mdx b/docs/references/javascript/types/custom-page.mdx new file mode 100644 index 0000000000..1fa7dd99e5 --- /dev/null +++ b/docs/references/javascript/types/custom-page.mdx @@ -0,0 +1,22 @@ +--- +title: CustomPage +description: An interface that provides the ability to add custom pages to the or components. +--- + +# `CustomPage` + +An interface that provides the ability to add custom pages to the [``][userprofile-ref] or [orgprofile-ref] components. + +## Attributes + +| Name | Type | Description | +| --- | --- | --- | +| `label` | `string` | The label of the custom page. It is a required property. | +| `url` | `string \| undefined` | The path segment that will be used to navigate to the custom page. It should be relative when providing a custom page and absolute when providing a custom link. | +| `mountIcon` | `((el: HTMLDivElement) => void) \| undefined` | This function is called to mount the icon of the label. The `el` argument is the element where the icon should be mounted. | +| `unmountIcon` | `((el?: HTMLDivElement) => void) \| undefined` | This function is called to unmount the icon of the label. The `el` argument is the same element that was passed to the `mountIcon` function. | +| `mount` | `((el: HTMLDivElement) => void) \| undefined` | This function is called to mount the content of the custom page. The `el` argument is the element where the content should be mounted. | +| `unmount` | `((el?: HTMLDivElement) => void) \| undefined` | This function is called to unmount the content of the custom page. The `el` argument is the same element that was passed to the `mount` function. | + +[userprofile-ref]: /docs/components/user/user-profile +[orgprofile-ref]: /docs/components/organization/organization-profile \ No newline at end of file