Docs

Build a sign-in flow with Clerk Elements

You will learn the following:

  • Build out different steps of an authentication flow
  • Accept user input through form fields
  • Verify a user's identity during a sign-in attempt
  • Support various password-related features

Note

  • Clerk Elements is for advanced use-cases that require a high-level of customization. The easiest way to implement Clerk is with our all-in-one UI components.

  • Clerk Elements currently only works with Next.js and Clerk Core 2. As it gets closer to a stable release, support for additional frameworks will be added.

Add a sign-in route

Create a new route in your Next.js application. The route needs to be an optional catch-all route so the sign-in flow can handled nested paths, as shown in the following example:

/app/sign-in/[[...sign-in]]/page.tsx
'use client'

import * as Clerk from '@clerk/elements/common'
import * as SignIn from '@clerk/elements/sign-in'

export default function SignInPage() {
  return (
    <SignIn.Root>
      [Sign In Root]
    </SignIn.Root>
  )
}

You will use these two imports to build out the rest of the flow. <SignIn.Root> manages the sign-in state and handles connecting the components to Clerk's APIs.

Tip

If you're getting TypeScript errors on the @clerk/elements imports you probably have forgotten to set your moduleResolution in tsconfig.json to bundler.

Add the start step

The Clerk authentication flows are made up of steps. Steps handle rendering the UI for each part of the flow. To allow users to create a sign-in attempt, the start step needs to be rendered. The following example does so with the <SignIn.Step> component:

/app/sign-in/[[...sign-in]]/page.tsx
'use client'

import * as Clerk from '@clerk/elements/common'
import * as SignIn from '@clerk/elements/sign-in'

export default function SignInPage() {
  return (
    <SignIn.Root>
      <SignIn.Step name="start">
        <h1>Sign in to your account</h1>
      </SignIn.Step>
    </SignIn.Root>
  )
}

Add form fields

Make it functional by adding input fields. The following example uses the <Clerk.Field> component to render an identifier field, as well as the <Connection> component to allow users to sign in with a social connection, like Google:

/app/sign-in/[[...sign-in]]/page.tsx
'use client'

import * as Clerk from '@clerk/elements/common'
import * as SignIn from '@clerk/elements/sign-in'

export default function SignInPage() {
  return (
    <SignIn.Root>
      <SignIn.Step name="start">
        <h1>Sign in to your account</h1>

        <Clerk.Connection name="google">
          Sign in with Google
        </Clerk.Connection>

        <Clerk.Field name="identifier">
          <Clerk.Label>Email</Clerk.Label>
          <Clerk.Input />
          <Clerk.FieldError />
        </Clerk.Field>

        <SignIn.Action submit>Continue</SignIn.Action>
      </SignIn.Step>
    </SignIn.Root>
  )
}

<Clerk.Field> takes care of wiring up the input with the label element, and <Clerk.FieldError> will render any field-specific errors that get returned from Clerk's API. The <SignIn.Action> component provides common actions that are used throughout the flows. In this case, using the submit action to render a submit button for the start form.

Note

If your Clerk instance supports signing in with Google and doesn't require multi-factor authentication (MFA), you should be able to complete a sign-in with the components rendered so far.

Add verification

As users progress through a sign-in attempt, they may be asked to verify a number of authentication factors in the verifications step. You can render a form for the user to complete verification, but each verification strategy requires different fields. You must render the form fields conditionally for each authentication strategy your instance supports using the <SignIn.Strategy> component.

The following example demonstrates how to conditionally render a form for the email_code strategy:

/app/sign-in/[[...sign-in]]/page.tsx
'use client'

import * as Clerk from '@clerk/elements/common'
import * as SignIn from '@clerk/elements/sign-in'

export default function SignInPage() {
  return (
    <SignIn.Root>
      <SignIn.Step name="start">
        <h1>Sign in to your account</h1>

        <Clerk.Connection name="google">
          Sign in with Google
        </Clerk.Connection>

        <Clerk.Field name="identifier">
          <Clerk.Label>Email</Clerk.Label>
          <Clerk.Input />
          <Clerk.FieldError />
        </Clerk.Field>

        <SignIn.Action submit>Continue</SignIn.Action>
      </SignIn.Step>

      <SignIn.Step name="verifications">
        <SignIn.Strategy name="email_code">
          <h1>Check your email</h1>
          <p>We sent a code to <SignIn.SafeIdentifier />.</p>

          <Clerk.Field name="code">
            <Clerk.Label>Email code</Clerk.Label>
            <Clerk.Input />
            <Clerk.FieldError />
          </Clerk.Field>

          <SignIn.Action submit>Continue</SignIn.Action>
        </SignIn.Strategy>
      </SignIn.Step>
    </SignIn.Root>
  )
}

Verification is the final step in the sign-in flow. When a user has verified all required factors, the sign-in attempt will be complete and they will be signed in.

Add password support

If your instance is configured to support authenticating with passwords, you must add a few additional steps and verification strategies. You can choose if you want to support providing a password in the start step with an additional field, or as an additional verification strategy. For this guide, add it as a standalone verification strategy.

/app/sign-in/[[...sign-in]]/page.tsx
'use client'

import * as Clerk from '@clerk/elements/common'
import * as SignIn from '@clerk/elements/sign-in'

export default function SignInPage() {
  return (
    <SignIn.Root>
      <SignIn.Step name="start">
        <h1>Sign in to your account</h1>

        <Clerk.Connection name="google">
          Sign in with Google
        </Clerk.Connection>

        <Clerk.Field name="identifier">
          <Clerk.Label>Email</Clerk.Label>
          <Clerk.Input />
          <Clerk.FieldError />
        </Clerk.Field>

        <SignIn.Action submit>Continue</SignIn.Action>
      </SignIn.Step>

      <SignIn.Step name="verifications">
        <SignIn.Strategy name="email_code">
          <h1>Check your email</h1>
          <p>We sent a code to <SignIn.SafeIdentifier />.</p>

          <Clerk.Field name="code">
            <Clerk.Label>Email code</Clerk.Label>
            <Clerk.Input />
            <Clerk.FieldError />
          </Clerk.Field>

          <SignIn.Action submit>Continue</SignIn.Action>
        </SignIn.Strategy>

        <SignIn.Strategy name="password">
          <h1>Enter your password</h1>

          <Clerk.Field name="password">
            <Clerk.Label>Password</Clerk.Label>
            <Clerk.Input />
            <Clerk.FieldError />
          </Clerk.Field>

          <SignIn.Action submit>Continue</SignIn.Action>
          <SignIn.Action navigate="forgot-password">
            Forgot password?
          </SignIn.Action>
        </SignIn.Strategy>

        <SignIn.Strategy name="reset_password_email_code">
          <h1>Check your email</h1>
          <p>We sent a code to <SignIn.SafeIdentifier />.</p>

          <Clerk.Field name="code">
            <Clerk.Label>Email code</Clerk.Label>
            <Clerk.Input />
            <Clerk.FieldError />
          </Clerk.Field>

          <SignIn.Action submit>Continue</SignIn.Action>
        </SignIn.Strategy>
      </SignIn.Step>

      <SignIn.Step name="forgot-password">
        <h1>Forgot your password?</h1>

        <SignIn.SupportedStrategy name="reset_password_email_code">
          Reset password
        </SignIn.SupportedStrategy>

        <SignIn.Action navigate="previous">Go back</SignIn.Action>
      </SignIn.Step>

      <SignIn.Step name="reset-password">
        <h1>Reset your password</h1>

        <Clerk.Field name="password">
          <Clerk.Label>New password</Clerk.Label>
          <Clerk.Input />
          <Clerk.FieldError />
        </Clerk.Field>

        <Clerk.Field name="confirmPassword">
          <Clerk.Label>Confirm password</Clerk.Label>
          <Clerk.Input />
          <Clerk.FieldError />
        </Clerk.Field>

        <SignIn.Action submit>Reset password</SignIn.Action>
      </SignIn.Step>
    </SignIn.Root>
  )
}

To enable users to reset their passwords, you can add the following additional steps:

  1. forgot-password – Renders <SignIn.SupportedStrategy>, which initiates the reset process, whereby an email code is sent to the user for verification.
    • <SignIn.SupportedStrategy> is also used in the forgot-password and choose-strategy steps to trigger verification of a supported strategy.
  2. reset-password – Allows a verified user to input a new password. If your instance has been set up to accept SMS codes, you can also use reset_password_phone_code.

Note

If your instance isn't configured to use passwords, or any of the strategies outlined here, Clerk Elements will log a warning to the console during development.

Customize and add styling

Learn how to style your Clerk Elements components with the styling guide.

For more extensive customization of the UI, check out additional Clerk Elements components such as <Loading> and <FieldState>.

Feedback

What did you think of this content?