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.
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 npm run format
.
- Fork and clone the repo
- Run
npm install
to install dependencies - Create a branch for your PR with
git checkout -b pr/your-branch-name
Tip: Keep your
main
branch 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 main
This will add the original repository as a "remote" called "upstream," Then fetch the git information from that remote, then set your local
main
branch to use the upstream main branch whenever you rungit pull
. Then you can make all of your pull request branches based on thismain
branch. 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 ("Leave a comment"): Describe what the concern was and summarize how you solved it.
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_LIST
insidecheck-links.mjs
.
To run all linting steps:
npm run lint
Once 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 navigation element rendered on https://clerk.com/docs is powered by the manifest file at /docs/manifest.json
. Making changes to this data structure will update the rendered navigation.
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'
}
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 to collapse the sub-nav
*
* @default false
*/
collapse?: boolean
}
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 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.
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
---
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
}
```
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
}
```
TypeScript type for code block props
type LineNumber = number
type Mark = LineNumber | [start: LineNumber, end: LineNumber]
interface CodeBlockProps {
filename?: string
mark?: Array<Mark>
ins?: Array<Mark>
del?: Array<Mark>
}
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.local' }}
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 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. Five 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.
The image below shows what this example looks like once rendered.
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>
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
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' . |
<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: 'App router',
link: 'https://github.com/clerk/clerk-nextjs-app-quickstart',
}
]}
>
- Install `@clerk/nextjs`
- Set up your environment keys to test your app locally
- Add `<ClerkProvider />` to your application
- Use Clerk middleware to implement route-specific authentication
- Create a header with Clerk components for users to sign in and out
</TutorialHero>
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
- ![alt text](/image.png)
---
- [title](href)
- description
- {<svg viewBox="0 0 32 32">{/* icon */}</svg>}
</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/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.
- {<svg viewBox="0 0 32 32">{/* */}</svg>}
---
- [UI Components](/docs/components/overview)
- Clerk's prebuilt UI components give you a beautiful, fully-functional user management experience in minutes.
- {<svg viewBox="0 0 32 32">{/* */}</svg>}
</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.
- {<svg viewBox="0 0 32 32">{/* */}</svg>}
---
- [UI Components](/docs/components/overview)
- Clerk's prebuilt UI components give you a beautiful, fully-functional user management experience in minutes.
- {<svg viewBox="0 0 32 32">{/* */}</svg>}
</Cards>
image
variant
<Cards variant="image">
- [What is Clerk authentication?](/docs/authentication/overview)
- 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-clerk.png)
---
- [What is the “User” object?](/docs/users/overview)
- 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.
- ![](/user-object.png)
</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.
- {<svg viewBox="0 0 32 32">{/* */}</svg>}
---
- [Need help?](/support 'Get help')
- Contact us through Discord, Twitter, or email to receive answers to your questions and learn more about Clerk.
- {<svg viewBox="0 0 32 32">{/* */}</svg>}
</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 <Include />
component can be used to inject the contents of another MDX file:
{/* Render `docs/_partials/oauth-instructions.mdx` */}
<Include src="_partials/oauth-instructions" />
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: ![Logo](/docs/images/logo.png)
.
Use the dark
prop to specify a different image to use in dark mode:
![Logo](/docs/images/logo.png){{ dark: '/docs/images/logo-dark.png' }}
You may also optionally provide the following next/image
props: quality
, priority
![Image](/docs/images/my-image.png){{ quality: 90, priority: true }}
When rendering images, make sure that you provide appropriate alternate text. Reference this decision tree for help picking a suitable value.
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!