Thanks for being willing to contribute to Clerk's documentation! This document outlines how to effectively contribute to the documentation content located in this repository. See the style guide for more information on our guidelines for writing content.
If you're contributing specifically to our hooks and components documentation, please refer to the dedicated guide.
Table of contents
- Contributing to Clerk's documentation
- Written in MDX
- Project setup
- Creating an issue
- Creating a pull request
- Preview your changes
- Validating your changes
- Getting your contributions reviewed
- Deployment
- Repository structure
- Editing content
- Help wanted!
Clerk's documentation content is written in a variation of markdown called MDX. MDX allows us to embed React components in the content, unlocking rich, interactive documentation experiences. Clerk's documentation site also supports GitHub Flavored Markdown, adding support for things like tables and task lists.
Clerk's documentation uses mdx-annotations which provides a consistent way to apply props to markdown elements. This is utilized for various features such as controlling image quality and defining code block line highlights.
MDX files (including any code blocks) are formatted using a custom Prettier plugin. It is recommended to enable "format on save" (or similar) in your code editor, but the formatter can also be run manually on all files using pnpm run format.
- Fork or clone the repo.
- Run
pnpm installto install dependencies. - Create a branch for your PR with
git checkout -b pr/your-branch-name.
Tip: If you forked the repo, keep your
mainbranch pointing at the original repository and make pull requests from branches on your fork. To do this, run:git remote add upstream https://github.com/clerk/clerk-docs.git git fetch upstream git branch --set-upstream-to=upstream/main mainThis will add the original repository as a "remote" called "upstream," Then fetch the git information from that remote, then set your local
mainbranch to use the upstream main branch whenever you rungit pull. Then you can make all of your pull request branches based on thismainbranch. Whenever you want to update your version ofmain, do a regulargit pull.
If you have found a contribution you would like to make, but it is rather large, it is recommended to open an issue first. Doing so not only helps keep track of what you plan to work on, but also facilitates discussions with maintainers, who can provide valuable feedback and ideas even before you begin implementing changes.
Modifications such as correcting misspelled words, addressing grammatical or punctuation errors, or making similar minor adjustments probably don't require the creation of an issue. In such cases, you are welcome to proceed by creating a pull request.
The structure of the issue should be:
- Title: Summarize the problem you want to solve in one sentence, using an active voice. E.g. "Fix broken "Home" link on sidenav"
- Description ("Leave a comment"): Discuss what your finding is, why it needs a solution, and where you found it/how it can be reproduced. Links, screenshots, and videos can be helpful tools!
When you're ready to submit your contribution, you're going to create a pull request, also referred to as a PR.
If this is your first time, or you need a refresher on how to create a PR, you can check out this video:
How to Contribute to an Open Source Project on GitHub
The structure of the PR should be:
- Title: Summarize the change you made, using an active voice. E.g. "Fix broken "Home" link on sidenav"
- If there is an issue that this PR is meant to resolve, the titles will probably be the same.
- Description: GitHub PRs are our source of truth, so descriptions should include as much relevant context as possible. Aim to be as detailed as possible (see example).
- If the PR is a result of a new feature or update, include links to the relevant source code PRs in their respective repos (e.g.
clerk/javascript) and clearly explain the behavior before —> now. If they areclerk/dashboardchanges, include screenshots/videos showing the before —> now updates. If this context already exists in the source code PR (clerk/javascript,clerk/dashboard,clerk/clerk, etc.), then just copy it over to theclerk-docsPR description, or vice-versa (if it’s inclerk-docsPR description, add it to the source code PR description). Writing up context shouldn’t be too hard - AI is very much your friend here! - The Deadline should always be filled out, even if the date is tentative/flexible. Try to provide a reasonable exact date so that it's trackable in the PR description. If there's truly no rush on it, write something like "No rush".
- If the PR is a result of a new feature or update, include links to the relevant source code PRs in their respective repos (e.g.
When you open a pull request, a member of the Clerk team can add the deploy-preview label to your pull request, which will trigger a preview deployment with your changes.
Clerk employees can run the application and preview their documentation changes locally. To do this, follow the instructions in the clerk README.
Before committing your changes, run our linting checks to validate the changes you are making are correct. Currently we:
- Check for broken links. If your change contains URLs that are not authored inside this repository (e.g. marketing pages or other docs) the linter will fail. You'll need to add your URLs to the
EXCLUDE_LISTinsidecheck-links.mjs. - Check that files are formatted with the prettier configuration settings.
- Check for changes to quickstarts.
To run all linting steps:
pnpm run lintOnce you open up a pull request with your changes, a member of the Clerk team will review your pull request and approve it, or leave addressable feedback. We do our best to review all contributions in a timely manner, but please be patient if someone does not take a look at it right away.
Once your pull request is approved, a member of the Clerk team will merge it and make sure it gets deployed! 🚀
The content rendered on https://clerk.com/docs is pulled from the main branch in this repository. If your PR is merged to the main branch, a workflow is triggered that updates the production pages. Changes should be reflected on https://clerk.com/docs within a matter of seconds.
The documentation content is located in the /docs directory. Each MDX file located in this directory will be rendered under https://clerk.com/docs at its path relative to the root /docs directory, without the file extension.
For example, the file at /docs/quickstarts/setup-clerk.mdx can be found at https://clerk.com/docs/quickstarts/setup-clerk.
The side navigation is powered by two things: the SDK selector and the manifest file at /docs/manifest.json.
The SDK selector allows a user to choose the SDK of their choice, and depending on the option they select, the sidenav will update to show docs specific to that SDK. For example, if you were to choose "Next.js", you would see the sidenav update to show docs that are scoped to Next.js.
- The logic for the SDK selector lives in
clerk/clerk, which is a private repository that is only available to Clerk employees. Therefore, to update the SDK selector, such as adding new items, you must be a Clerk employee. For instructions on how to do so, see this section. If you aren't a Clerk employee but have suggestions or concerns, please submit an issue.
The manifest.json is responsible for the structure of the sidenav, including setting the title and link for each sidenav item. Below is some helpful information on the typing and structure of the file.
Equivalent TypeScript types and descriptions
export type Nav = Array<NavGroup>
/**
* Nav groups are separated by horizontal rules
*/
type NavGroup = Array<NavItem>
/**
* A nav item is either a link, or a sub-list with nested `items`
*/
type NavItem = LinkItem | SubNavItem
/**
* A link to an internal or external page
*/
type LinkItem = {
/**
* The visible item text. May contain backticks (`) to render `<code>`
*
* @example 'Next.js Quickstart'
* @example '`<SignIn>` and `<SignUp>`'
*/
title: string
/**
* The item link. Internal links should be relative
*
* @example '/docs/quickstarts/nextjs'
* @example 'https://example.com'
*/
href: string
/**
* Muted text to display next to the item text
*
* @example 'Community'
* @example 'Beta'
*/
tag?: string
/**
* Icon to display next to the item text
*
* @example 'globe'
* @see [Available icons]{@link https://github.com/clerk/clerk/blob/main/src/app/(website)/docs/icons.tsx}
*/
icon?: string
/**
* Whether to enable text wrapping for the item text
*
* @default true
*/
wrap?: boolean
/**
* Set to "_blank" to open link in a new tab
*/
target?: '_blank'
/**
* Limit this page to only show when the user has one of the specified sdks active
*
* @example ['nextjs', 'react']
*/
sdk?: string[]
}
type SubNavItem = {
/**
* The visible item text. May contain backticks (`) to render `<code>`
*
* @example 'Next.js Quickstart'
* @example '`<SignIn>` and `<SignUp>`'
*/
title: string
/**
* The nested sub-items
*/
items: Nav
/**
* Muted text to display next to the item text
*
* @example 'Community'
* @example 'Beta'
*/
tag?: string
/**
* Icon to display next to the item text
*
* @example 'globe'
* @see [Available icons]{@link https://github.com/clerk/clerk/blob/main/src/app/(website)/docs/icons.tsx}
*/
icon?: string
/**
* Whether to enable text wrapping for the item text
*
* @default true
*/
wrap?: boolean
/**
* Whether the nav item is in the top part of the sidebar navigation
*
* @default false
*/
topNav?: boolean
/**
* Limit this group to only show when the user has one of the specified sdks active
*
* @example ['nextjs', 'react']
*/
sdk?: string[]
}For Clerk employees only. (Why?)
To update the SDK selector, the files you need are in clerk/clerk:
- https://github.com/clerk/clerk/blob/main/src/app/(website)/docs/SDKSelector.tsx
- This is the logic behind how the SDK selector works and sets an SDK as active for the Docs. It's unlikely you'll touch this file, unless you are changing the logic behind how the SDK selector works.
- https://github.com/clerk/clerk/blob/main/src/app/(website)/docs/SDK.tsx
- This is the source of truth for the SDK selector. The
sdksobject includes the list of available SDKs and renders in the order it's formatted as; we like to have the most used SDKs at the top (Next.js, React, JavaScript), and then the rest are alphabetized.
- This is the source of truth for the SDK selector. The
If the SDK has docs that are internal, i.e. maintained in clerk-docs, then follow these instructions. If the SDK has docs that are external, e.g. Python located at https://github.com/clerk/clerk-sdk-python/blob/main/README.md, then see the section on adding an external SDK.
To add a new SDK, you'll need the SDK name (e.g. Next.js), key (e.g. nextjs), and 2 SVG icons: one in color and one in grayscale. These must be converted to JSX syntax, not HTML / standard SVG syntax. You will need these SVG's because we list the Clerk SDK's on https://clerk.com/docs, https://clerk.com/docs/reference/overview, and if there is a quickstart for it, https://clerk.com/docs/quickstarts/overview.
In this repo (clerk/clerk-docs):
- In the
manifest.schema.json, add a reference name in theiconenum and add the SDK key to thesdkenum. - Add the color SVG to the partials icon folder
_partials/icons/. - Add the SDK to
index.mdx,reference/overview.mdx, and if there is a quickstart for it,quickstarts/overview.mdx. - In the
manifest.json, find the"title": "Clerk SDK",object. It should be the first object in the"navigation"array. Add the SDK accordingly. For example, it could include files like a quickstart, a references section with an overview and some reference docs, or a guides section with some dedicated guides for that SDK.
Now, the sidenav is set up to render the items for the new SDK you've added, and to link to the routes/doc files that you defined. However, you've got to get the SDK selector working as well:
In the clerk/clerk repo:
- In the
app/(website)/docs/icons.tsxfile, add the SVGs. The grayscale version goes in theiconsobject while the color version goes in theiconsLargeobject. Use the same key for both. - In the
app/(website)/docs/SDK.tsxfile, update thesdksobject to include your new SDK. You should pass at least the following keys:title,icon,route,category.
If the SDK has docs that are external, e.g. Python located at https://github.com/clerk/clerk-sdk-python/blob/main/README.md, then follow these instructions. If the SDK has docs that are internal, i.e. maintained in clerk-docs, then see the section on adding a new SDK.
To add a new SDK, you'll need the SDK name (e.g. Python), key (e.g. python), and 2 SVG icons: one in color and one in grayscale. These must be converted to JSX syntax, not HTML / standard SVG syntax. You will need these SVG's because we list the Clerk SDK's on https://clerk.com/docs and https://clerk.com/docs/reference/overview.
In this repo (clerk/clerk-docs):
- In the
manifest.schema.json, add a reference name in theiconenum and add the SDK key to thesdkenum. - Add the color SVG to the partials icon folder
_partials/icons/. - Add the SDK to
index.mdxandreference/overview.mdx.
Now, the sidenav is set up to render the items for the new SDK you've added, and to link to the routes/doc files that you defined. However, you've got to get the SDK selector working as well:
In the clerk/clerk repo:
- In the
app/(website)/docs/icons.tsxfile, add the SVGs. The grayscale version goes in theiconsobject while the color version goes in theiconsLargeobject. Use the same key for both. - In the
app/(website)/docs/SDK.tsxfile, update thesdksobject to include your new SDK. You should pass at least the following keys:title,icon,external,category.
If you need to update the key of an SDK, because the logic is shared in clerk-docs and clerk/clerk repo's, both the old and the new keys must be kept as available. This is similar to deprecating an old key, and releasing a new key - you must still support the old key.
In the clerk/clerk repo:
-
In
clerk/src/app/(website)/docs/SDK.tsx, change the necessary key in thesdksobject. -
In that same file, update the
sdkKeyMigrationsobject by adding the old key as the key and the new key as the value. For example, if you were changing thesdkkey to bejsinstead ofjavascript, you would do the following updates:const sdks = { - 'javascript': { + 'js': { ... } } const sdkKeyMigrations = { + 'javascript': 'js', }
Then, in this repo (clerk-docs):
- In the
manifest.schema.json, update thesdkenum to use the new key. - In the
manifest.json, update thesdkarrays to use the new key. - Find all uses of the
<If />component that uses the old key and update them to use the new key.
As mentioned above, all of the documentation content is located in the /docs directory. If you are having trouble finding the file associated with a specific page on the live documentation site, try clicking the "Edit this page on GitHub" link.
Each file has a few required frontmatter fields, which are defined like so:
---
title: Page title
description: Some brief, but effective description of the page's content.
---title- The title of the page. Used to populate the HTML<title>tag and the h1 of the page. Supports markdown e.g.title: '`<SignUp>`'description- The description of the page. Used to populate a page's<meta name="description">tag
These fields should be present on every documentation page.
The metadata frontmatter field can be used to define additional information about a documentation page, such as SEO metadata, social sharing tags, or indexing information. It allows you to control how the page appears in browsers, search engines, and social media previews. It has the following subfields:
| Name | Type | Default | Description |
|---|---|---|---|
title |
string |
- | Overrides the browser title and <title> meta tag. |
description |
string |
- | Overrides the meta description shown in search results and link previews. |
authors |
Array<{ name: string }> |
[] |
Lists the authors of the page for structured data or article metadata. |
alternates |
object |
{} |
Defines canonical and alternate URLs for the page. See its properties below. |
openGraph |
object |
{} |
Configures Open Graph data for social previews (Facebook, LinkedIn, etc). See its properties below. |
twitter |
object |
{} |
Configures X Cards data for previews on X (Twitter). See its properties below. |
robots |
object |
{} |
Controls how crawlers index and follow the page. See its properties below. |
Set a custom browser title
---
title: Example
+ metadata:
+ title: Example
---Set SEO title and description
---
title: Example
+ metadata:
+ title: Example
+ description: Example
---Add page authors
---
title: Example
+ metadata:
+ authors:
+ - name: Jane Doe
---Define canonical or alternate URLs for your documentation page
This is set via the alternates field. It has the following subfields:
| Name | Type | Default | Description |
|---|---|---|---|
canonical |
string |
- | The canonical URL to avoid duplicate content across versions or domains. |
---
title: Example
+ metadata:
+ alternates:
+ canonical: https://docs.example.com/
---Configure Open Graph metadata for social media previews
This is set via the openGraph field. It has the following subfields:
| Name | Type | Default | Description |
|---|---|---|---|
title |
string |
- | Title displayed in social previews. |
description |
string |
- | Description displayed in social previews. |
images |
Array<string> |
[] |
One or more image URLs for preview cards. |
publishedTime |
string |
- | Publication timestamp. |
authors |
Array<string> |
[] |
Author names associated with the page. |
---
title: Example
+ metadata:
+ openGraph:
+ title: Clerk Organizations - invite users
+ description: Guide to sending and managing invitations within Clerk.
+ images:
+ - https://example.com/social-preview.png
---Define X Cards metadata for the page
This is set via the twitter field. It has the following subfields:
| Name | Type | Default | Description |
|---|---|---|---|
title |
string |
- | Title displayed in the Twitter card. |
description |
string |
- | Description displayed in the Twitter card. |
images |
Array<string> |
[] |
Image URLs used in the Twitter card preview. |
---
title: Example
+ metadata:
+ twitter:
+ title: Clerk Organizations - invite users
+ description: Guide to sending and managing invitations within Clerk.
+ images:
+ - https://example.com/social-preview.png
---Control search engine indexing and crawler behavior.
This is set via the robots field. It has the following subfields:
| Name | Type | Default | Description |
|---|---|---|---|
index |
boolean |
true |
Whether the page should appear in search results. |
follow |
boolean |
true |
Whether crawlers should follow links from this page. |
---
title: Example
+ metadata:
+ robots:
+ index: false
+ follow: true
---The search frontmatter field can be used to control how a page is indexed by Algolia Crawler. It has the following subfields:
| Name | Type | Default | Description |
|---|---|---|---|
exclude |
boolean |
false |
Whether to exclude the page from search entirely |
rank |
number |
0 |
The value to use for weight.pageRank in the index. See Custom Ranking and Boost search results with pageRank |
keywords |
Array<string> |
[] |
Additional searchable keywords to include when indexing the page. These are not visible to users. |
You may also set search to a boolean value, which acts as an exclude value. See the first example below.
The preview frontmatter field can be used to render a component preview at the start of the page. It has the following subfields:
| Name | Type | Default | Description |
|---|---|---|---|
src |
string |
N/A | The URL path to the live preview (e.g., /sign-in) |
shadcn |
object |
N/A | Optional object containing framework-specific shadcn component names for installation references that renders a button to copy the shadcn install command |
The shadcn subfield supports the following framework keys:
| Name | Type | Description |
|---|---|---|
nextjs |
string |
The name of the Next.js Shadcn component (e.g., nextjs-sign-in-page) |
Add a preview with live demo
---
title: Example
+ preview:
+ src: '/sign-in'
---Add a preview with Shadcn component reference
---
title: Example
+ preview:
+ src: '/sign-in'
+ shadcn:
+ nextjs: 'nextjs-sign-in-page'
---Exclude a page from search
---
title: Example
+ search: false
---Boost a page in search results
---
title: Example
+ search:
+ rank: 1
---Show a page in results when searching for "supercalifragilisticexpialidocious"
---
title: Example
+ search:
+ keywords:
+ - supercalifragilisticexpialidocious
---The sdk frontmatter field defines what SDKs a page supports and makes the page visible in the sidenav only when one of those SDKs is selected by the SDK selector.
For example, if nextjs and react were passed to the sdk frontmatter field, like so:
---
title: `'<ClerkProvider>'`
description: Lorem ipsum...
+ sdk: nextjs, react
---This does a couple things:
- URL's are generated for this page per specified SDK. In this case, for the
/docs/clerk-provider.mdxfile,/docs/nextjs/clerk-providerand/docs/react/clerk-providerwill be generated. One fornextjsand one forreact.- The base url
/docs/clerk-providerwill still exist, but will show a grid of the available variants.
- The base url
- The page will only show up in the sidenav if the user has one of the specified SDKs "active", which means selected in the SDK selector.
- Links to this page will be "smart" and direct the user towards the correct variant of the page based on which SDK is active.
- On the right side of the page, a selector will be shown, allowing the user to switch between the different versions of the page.
A doc variant is a version of a page that is specific to a particular SDK. For example, the quickstart.react.mdx page is a variant of the quickstart.mdx page that is specific to the React SDK. This is useful when you want to show different content for different SDKs but want to keep the route the same.
Note
When creating doc variants, there will be a base doc that is used as the reference for the variants. Take the example from before, quickstart.mdx would be the base doc. Base docs should always be written for Next.js as it's our most popular and maintained SDK.
When would I use a doc variant?
Say you have a doc where you want to support multiple SDKs, but it'd require changing a majority of the content for each SDK. Instead of using a bunch of <Tabs /> or <If /> components, which would bloat the doc and make it harder to maintain, you can create a doc variant.
Headings should be nested by their rank. Headings with an equal or higher rank start a new section, headings with a lower rank start new subsections that are part of the higher ranked section. Please see the Web Accessibility Initiative documentation for more information.
Headings should be written in sentence-casing, where only the first word of the heading is capitalized. E.g. "This is a heading".
h1's are not necessary and are considered tech-debt, as the title property in the frontmatter will set the h1.
h2 and h3 headings are automatically included in the table of contents. You can control this behaviour by using the toc prop:
{/* Replace the text for this heading in the table of contents */}
## Lorem ipsum {{ toc: 'Hello world' }}
{/* Exclude heading from table of contents */}
## Lorem ipsum {{ toc: false }}Headings are automatically assigned an id attribute which is a slugified version of the text content. You can optionally override this by providing an id prop:
{/* Replace the generated ID (`lorem-ipsum`) with `lipsum` */}
## Lorem ipsum {{ id: 'lipsum' }}Syntax-highlighted code blocks are rendered wherever markdown code blocks are used. To add syntax highlighting, specify a language next to the backticks before the fenced code block.
```typescript
function add(a: number, b: number) {
return a + b
}
```
You can also specify a filename by passing the filename prop.
```typescript {{ filename: 'add.ts' }}
function add(a: number, b: number) {
return a + b
}
```
If the code should run in a terminal, you can set the syntax highlighting to something like sh (shell) or bash. The file name should be set to terminal.
```sh {{ filename: 'terminal' }}
npm i @clerk/nextjs
```
You can highlight specific lines in a code block using the mark prop. For example, to highlight line 2 and lines 5-7:
```tsx {{ mark: [2, [5, 7]] }}
export function Page() {
return null
}
export function Layout() {
return null
}
```You can also highlight specific strings using the mark prop. For example, to highlight cssLayerName: 'clerk':
```tsx {{ mark: ["cssLayerName: 'clerk'"] }}
<ClerkProvider
appearance={{
cssLayerName: 'clerk',
}}
>
```The ins (insert) and del (delete) props work in the same way as the mark prop but apply "diff" style highlighting with prepended + and - signs.
ins and del example
```tsx {{ ins: [2], del: [[5, 7]] }}
export function Page() {
return null
}
export function Layout() {
return null
}
```You can also specify deleted, inserted, or marked lines by prepending them with a special character. This is available for any code block language except Markdown.
| Type | Character |
|---|---|
| Deleted | - |
| Inserted | + |
| Marked | = |
```tsx
export function App() {
- return <Foo />
+ return <Bar />
}
```You can collapse sections of a code block by using the fold prop. The type for the fold prop is Array<[start: number, end: number, label?: string]>, where start and end define the inclusive range of lines to collapse, and label is a custom label for the expand button. By default the label will be {n} lines collapsed.
```ts {{ fold: [[2, 4]] }}
export function Example() {
useEffect(() => {
// some long unimportant code here
}, [])
return null
}
```You can also truncate a code block by using the collapsible prop. This will reduce the height of the code block by default and display an "expand" button to reveal the full code block.
```ts {{ collapsible: true }}
// ...
```type LineNumber = number
type Mark = LineNumber | [start: LineNumber, end: LineNumber]
interface CodeBlockProps {
filename?: string
mark?: Array<Mark>
ins?: Array<Mark>
del?: Array<Mark>
collapsible?: boolean
fold?: Array<[start: LineNumber, end: LineNumber, label?: string]>
}You can use the following shortcodes within a code block to inject information from the user's current Clerk instance:
{{pub_key}}– Publishable Key{{secret}}– Secret Key{{fapi_url}}– Frontend API URL
```sh {{ filename: '.env' }}
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY={{pub_key}}
CLERK_SECRET_KEY={{secret}}
```The video below shows what this example looks like once rendered. Notice the eye icon on the code block that once clicked on, reveals the user's Secret Key.
code-block-keys.mp4
Code within code blocks is automatically formatted by Prettier when the containing MDX file is formatted. Formatting errors may occur due to invalid syntax and these will cause the "Lint" GitHub action to fail and prevent pull requests from being merged. This is a deliberate tool to help prevent syntax errors from finding their way into code examples.
Formatting can be disabled for a code block by setting the prettier prop to false, but this should only be used when absolutely necessary:
```tsx {{ prettier: false }}
// ...
```"prettier-ignore" comments are also supported to ignore parts of a code block. This is preferred over the prettier prop where possible:
```tsx
console.log('not ignored')
// prettier-ignore
console.log('ignored')
```Note
"prettier-ignore" comments are removed when a code block is rendered on the docs site.
The <Steps /> component is used to number a set of instructions with an outcome. It uses the highest heading available in the component to denote each step. Can be used with h2 and h3 headings.
<Steps>
## Step 1
Do these actions to complete Step 1.
## Another step
### A heading inside a step
Do these actions to complete Step 2.
</Steps>The image below shows what this example looks like once rendered.
A callout draws attention to something learners should slow down and read.
Note
Callouts can be distracting when people are quickly skimming a page. So only use them if the information absolutely should not be missed!
Callout syntax is based on GitHub's markdown "alerts". To add a callout, use a special blockquote line specifying the callout type, followed by the callout information in a standard blockquote. The following types of callouts are available:
> [!NOTE]
> Useful information that users should know, even when skimming content.
> [!TIP]
> Helpful advice for doing things better or more easily.
> [!IMPORTANT]
> Key information users need to know to achieve their goal.
> [!WARNING]
> Urgent info that needs immediate user attention to avoid problems.
> [!CAUTION]
> Advises about risks or negative outcomes of certain actions.
> [!QUIZ]
> An opportunity for users to check their understanding.The image below shows what this example looks like once rendered.
You can optionally specify an id attribute for a callout which allows for direct linking, e.g. /docs/example#useful-info:
> [!NOTE useful-info]
> Useful information that users should know, even when skimming content.You can create a collapsible section within a callout by using a thematic break (---). Content following the break is hidden by default and can be toggled by the user:
> [!QUIZ]
> Why does handshake do a redirect? Why can’t it make a fetch request to FAPI and get a new token back that way? Not needing to redirect would be a better user experience.
>
> ---
>
> Occaecati esse ut iure in quam praesentium nesciunt nemo. Repellat aperiam eaque quia. Aperiam voluptatem consequuntur numquam tenetur. Quibusdam repellat modi qui dolor ducimus ut neque adipisci dolorem. Voluptates dolores nisi est fuga.The <CodeBlockTabs /> component renders multiple variations of a code block. It accepts an options property, which is an array of strings. For each option provided, it renders a code block.
<CodeBlockTabs options={['npm', 'yarn', 'pnpm']}>
```sh {{ filename: 'terminal' }}
npm i @clerk/nextjs
```
```sh {{ filename: 'terminal' }}
yarn add @clerk/nextjs
```
```sh {{ filename: 'terminal' }}
pnpm add @clerk/nextjs
```
</CodeBlockTabs>npm codeblocks will automatically generate the commands for pnpm, yarn, and bun within a <CodeBlockTabs />.
```npm
npm i @clerk/nextjs
```Example output:
<CodeBlockTabs options={["npm", "pnpm", "yarn", "bun"]}>
```bash {{ filename: 'terminal' }}
npm i @clerk/nextjs
```
```bash {{ filename: 'terminal' }}
pnpm add @clerk/nextjs
```
```bash {{ filename: 'terminal' }}
yarn add @clerk/nextjs
```
```bash {{ filename: 'terminal' }}
bunx add @clerk/nextjs
```
</CodeBlockTabs>The image below shows what this example looks like once rendered.
The <Tabs /> component structures content in a tabular format. It accepts an items property, which is an array of strings. For each option provided, it renders a <Tab /> component, as shown in the example below.
<Tabs items={['React', 'JavaScript']}>
<Tab>
Here is some example text about React.
</Tab>
<Tab>
Here is some example text about JavaScript.
</Tab>
</Tabs>The video below shows what this example looks like once rendered.
tabs.mp4
A tooltip is content that appears when the user hovers over a word or phrase in order to provide additional information. A common use case is for definitions.
Tooltips are defined in the _tooltips folder and written in MDX, but they do not support custom MDX components, like callouts or <Tabs /> components. Try to keep the tooltip content as text.
The tooltip syntax is similar to a link, but with a ! prefix, as shown in the following example:
The ID of the [Active Organization](!active-organization) that the user belongs to.Tooltips should follow the same styleguide as links - only add them on the first mention of a term and only in the highest heading section. So if a term is mentioned in an H2 section and again in its H3 section, it doesn't need to be added in the H3 section.
The <TutorialHero /> component is used at the beginning of a tutorial-type content page. It accepts the following properties:
| Property | Type | Description |
|---|---|---|
beforeYouStart |
{ title: string; link: string; icon: string }[] | Links to things that learners should complete before the tutorial. |
exampleRepo (optional) |
{ title: string; link: string }[] | Links to example repositories. |
exampleRepoTitle (optional) |
string | The title for the example repository/repositories. Defaults to 'Example repository' or 'Example repositories', but can be passed any string. |
<TutorialHero
beforeYouStart={[
{
title: 'Set up a Clerk application',
link: '/docs/quickstarts/setup-clerk',
icon: 'clerk',
},
{
title: 'Create a Next.js application',
link: 'https://nextjs.org/docs/getting-started/installation',
icon: 'nextjs',
},
]}
exampleRepo={[
{
title: 'Clerk + Next.js App Router Quickstart',
link: 'https://github.com/clerk/clerk-nextjs-app-quickstart',
},
]}
/>The <Cards> component can be used to display a grid of cards in various styles.
Cards uses Markdown list syntax with each card separated by three dashes ---.
<Cards>
- [title](href)
- description
---
- [title](href)
- description
- 
---
- [title](href)
- description
-  (preferred) or {<svg viewBox="0 0 32 32">{/* icon */}</svg>} or <Icon name="clerk" />
</Cards>| Property | Type | Description |
|---|---|---|
variant |
'default' | 'plain' | 'cta' | 'image' |
The visual style of the cards, default: 'default' (see examples below) |
cols |
2 | 3 | 4 |
The number of columns in the card grid, default: 2 |
level |
2 | 3 | 4 |
The level to use for the card headings, default: 3 |
default variant
<Cards>
- [Quickstarts & Tutorials](/docs/quickstarts/overview)
- Explore our end-to-end tutorials and getting started guides for different application stacks using Clerk.
---
- [UI Components](/docs/reference/components/overview)
- Clerk's prebuilt UI components give you a beautiful, fully-functional user management experience in minutes.
</Cards>default variant with icons
<Cards>
- [Quickstarts & Tutorials](/docs/quickstarts/overview)
- Explore our end-to-end tutorials and getting started guides for different application stacks using Clerk.
-  (preferred) or {<svg viewBox="0 0 32 32">{/* icon */}</svg>} or <Icon name="clerk" />
---
- [UI Components](/docs/reference/components/overview)
- Clerk's prebuilt UI components give you a beautiful, fully-functional user management experience in minutes.
-  (preferred) or {<svg viewBox="0 0 32 32">{/* icon */}</svg>} or <Icon name="clerk" />
</Cards>plain variant with icons
<Cards variant="plain">
- [Quickstarts & Tutorials](/docs/quickstarts/overview)
- Explore our end-to-end tutorials and getting started guides for different application stacks using Clerk.
-  (preferred) or {<svg viewBox="0 0 32 32">{/* icon */}</svg>} or <Icon name="clerk" />
---
- [UI Components](/docs/reference/components/overview)
- Clerk's prebuilt UI components give you a beautiful, fully-functional user management experience in minutes.
-  (preferred) or {<svg viewBox="0 0 32 32">{/* icon */}</svg>} or <Icon name="clerk" />
</Cards>image variant
<Cards variant="image">
- [What is Clerk authentication?](/docs/guides/configure/auth-strategies/sign-up-sign-in-options)
- Clerk offers multiple authentication strategies to identify legitimate users of your application, and to allow them to make authenticated requests to your backend.
- 
---
- [What is the “User” object?](/docs/guides/users/managing)
- The User object contains all account information that describes a user of your app in Clerk. Users can authenticate and manage their accounts, update their personal and contact info, or set up security features for their accounts.
- 
</Cards>cta variant
<Cards variant="cta">
- [Join our Discord](/discord 'Join Discord')
- Join our official Discord server to chat with us directly and become a part of the Clerk community.
-  (preferred) or {<svg viewBox="0 0 32 32">{/* icon */}</svg>} or <Icon name="clerk" />
---
- [Need help?](/support 'Get help')
- Contact us through Discord, Twitter, or email to receive answers to your questions and learn more about Clerk.
- ![alt text(/docs/images/path/to/file.svg) (preferred) or {<svg viewBox="0 0 32 32">{/* icon */}</svg>} or <Icon name="clerk" />
</Cards>The <Properties> component can be used to display a list of properties.
Properties uses Markdown list syntax with each property separated by three dashes ---.
<Properties>
- `name`
description
---
- `name`
- `type`
description
description continued…
</Properties>Note
Typically name and type would make use of inline code (`) but this not required
Example
<Properties>
- `path`
- `string`
The root path the sign-in flow is mounted at. Default: `/sign-in`
---
- `fallback`
- `React.ReactNode`
Fallback markup to render while Clerk is loading. Default: `null`
</Properties>The <ComparisonTable> component is used to create feature comparison tables with styled checkmarks, X marks, and section headers. The table header stays sticky when scrolling the page.
| Component | Description |
|---|---|
<ComparisonTable> |
Wrapper component for the comparison table with sticky header |
<CompareSection> |
Creates a section header row that spans all columns |
<CompareYes /> |
Displays a green checkmark (✓). Use inline prop for inline display |
<CompareNo /> |
Displays a red X (✗). Use inline prop for inline display |
<ComparePartial> |
Displays orange text. Defaults to "◐", accepts custom children |
<CompareNotApplicable> |
Displays gray text. Defaults to "—", accepts custom children |
<ComparisonTable>
<thead>
<tr>
<th>Feature</th>
<th>Basic</th>
<th>Pro</th>
</tr>
</thead>
<tbody>
<CompareSection>Authentication</CompareSection>
<tr>
<td>Email/Password</td>
<td>
<CompareYes />
</td>
<td>
<CompareYes />
</td>
</tr>
<tr>
<td>Social Login</td>
<td>
<CompareNo />
</td>
<td>
<CompareYes />
</td>
</tr>
<tr>
<td>MFA</td>
<td>
<ComparePartial>Limited</ComparePartial>
</td>
<td>
<CompareYes />
</td>
</tr>
</tbody>
</ComparisonTable>Use the inline prop on <CompareYes /> and <CompareNo /> when you need them inline with text:
The feature was removed (was <CompareYes inline />, now <CompareNo inline />).The <Include /> component can be used to inject the contents of another MDX file. We like to use this component to include partial files that are used in multiple pages. This way, you write the content once and only have to maintain it in one place.
There are two types of partials you can use:
- Global partials - Located in
/docs/_partials/and can be referenced from any document. - Relative partials - Located in
_partials/folders within any subdirectory and are scoped to documents near them.
Global partials are stored in /docs/_partials/ and can be included from any document using a path starting with _partials/:
{/* Render `docs/_partials/code-example.mdx` */}
<Include src="_partials/code-example" />Global partials are best for:
- Content that is reused across many different sections of the documentation.
- Shared components, code examples, or explanations that apply broadly.
- Content that doesn't belong to a specific topic area.
Relative partials are stored in _partials/ folders within subdirectories and can be included using relative paths (./ or ../). The path is resolved relative to the document's directory.
Same directory:
If you have a document at docs/billing/for-b2c.mdx and a partial at docs/billing/_partials/pricing-table.mdx:
<Include src="./_partials/pricing-table" />Parent directory:
If you have a document at docs/billing/plans/premium.mdx and a partial at docs/billing/_partials/shared-content.mdx:
<Include src="../_partials/shared-content" />Relative partials are best for:
- Content that is specific to a particular section or topic area (e.g., billing-specific instructions).
- Content that is only used by a few documents in the same directory structure.
- Organizing partials near the documents that use them for better maintainability.
The <Typedoc /> component is used to inject the contents of an MDX file from the ./clerk-typedoc folder. The files inside that folder are not manually created and maintained; they are automatically created from the clerk/javascript repository. This has a couple of implications:
- If you want to edit the contents of a file that contains a
<Typedoc />component, you'll have to open a pull request inclerk/javascriptand change the source file's JSDoc comment. For information on how to author Typedoc comments, see this section. - Once your PR in
clerk/javascripthas been merged and a release is published, a PR will be opened inclerk-docsto merge in the Typedoc changes.
For example, in the /hooks/use-auth.mdx file, if you want to render ./clerk-typedoc/clerk-react/use-auth.mdx, you would embed the <Typedoc /> component like this:
<Typedoc src="clerk-react/use-auth" />The <If /> component is used for conditional rendering. When the conditions are true, it displays its contents. When the conditions are false, it hides its contents. We commonly use this component to conditionally render content based on the active SDK. The active SDK is the SDK that is selected in the sidenav.
If you'd like to add support for a new SDK in a guide, but using the <If /> component in the doc is getting too noisy, another option is to create a doc variant.
Important
This component cannot be used within code blocks.
| Props | Type | Comment |
|---|---|---|
children |
React.ReactNode |
The content that will be conditionally rendered. |
condition? (optional) |
boolean |
The condition that determines if the content is rendered. |
sdk? (optional) |
string | string[] |
Filter the content to only display based on the passed SDK(s). For example, if the sdk prop is set to ['nextjs', 'react'], the content will only be rendered if the active SDK is Next.js or React. |
notSdk? (optional) |
string | string[] |
Filter the content to only display based on the SDK(s) that were NOT passed. For example, if the notSdk prop is set to ['nextjs', 'react'], the content will only be rendered if the active SDK is NOT Next.js or React. |
Available values for the sdk prop:
| SDK | Value |
|---|---|
| Next.js | "nextjs" |
| React | "react" |
| Javascript | "js-frontend" |
| Chrome Extension | "chrome-extension" |
| Expo | "expo" |
| Android | "android" |
| iOS | "ios" |
| Express | "expressjs" |
| Fastify | "fastify" |
| React Router | "react-router" |
| Remix | "remix" |
| Tanstack React Start | "tanstack-react-start" |
| Go | "go" |
| Astro | "astro" |
| Nuxt | "nuxt" |
| Vue | "vue" |
| Ruby / Rails / Sinatra | "ruby" |
| Python | "python" |
| JS Backend SDK | "js-backend" |
| Community SDKs | "community-sdk" |
To update the value, or key, for an SDK, see the section on updating the key of an SDK.
Filtered to a single SDK
<If sdk="nextjs">This content will only be rendered if the active SDK is Next.js</If>Filtered to either the Astro or React active SDK
<If sdk={['astro', 'react']}>This content will only be rendered if the active SDK is Astro or React</If>Filter within a filter
<If sdk={['nextjs', 'remix']}>
This content will only be rendered if the active SDK is Next.js or Remix.
<If sdk="nextjs">This content will only be rendered if the active SDK is Next.js</If>
</If>Filter to all SDKs except the ones passed
<If notSdk="nextjs">This content will only be rendered if the active SDK is **NOT** Next.js</If>The <Accordion /> component creates a vertically stacked set of interactive headings that each reveals a section of content. It has no props and accepts <AccordionPanel /> children.
The <AccordionPanel /> accepts a title and children.
| Prop | Type | Comment |
|---|---|---|
children |
React.ReactNode |
The content that will be rendered in the accordion panel. |
title |
string |
The title of the accordion panel. |
<Accordion>
<AccordionPanel title="Can I use this?">It's available in v1.2.3 and above.</AccordionPanel>
<AccordionPanel title="What if I still have questions?">Send and email to help@example.com.</AccordionPanel>
</Accordion>The image below shows what this example looks like once rendered.
Images and static assets should be placed in the public/ folder. To reference an image or asset in content, prefix the path with /docs. For example, if an image exists at public/images/logo.png, to render it on a page you would use the following: .
When rendering images, make sure that you provide appropriate alternate text. Reference this decision tree for help picking a suitable value.
Image captions can be added using standard Markdown "title" syntax. For example, 
dark
Use the `dark` prop to specify a different image to use in dark mode:
{{ dark: '/docs/images/logo-dark.png' }}priority
https://nextjs.org/docs/app/api-reference/components/image#priority
{{ priority: true }}quality
https://nextjs.org/docs/app/api-reference/components/image#quality
{{ quality: 90 }}width and height
The `width` and `height` props can now be used to specify the (max) display size of an image in pixels.
{{ width: 345 }}Without width |
With width |
|---|---|
![]() |
![]() |
align
align can be set to left, center, or right to align an image horizontally. The default is left.
left |
center |
right |
|---|---|---|
![]() |
![]() |
![]() |
variant
The variant prop can be used to display an image in a different style. Possible values are default and browser.
default |
browser |
|---|---|
![]() |
![]() |
When using the browser variant the caption is displayed in the menu bar.
The Gallery component displays multiple images in a grid layout. On mobile the images are laid out horizontally in a scrollable container.
Example
<Gallery>


</Gallery>
| Desktop | Mobile |
|---|---|
![]() |
![]() |
Looking to contribute? Please check out the open issues for opportunities to help out. Thanks for taking the time to help make Clerk's docs better!























