Styling for Clerk Elements
You can style Clerk Elements components with the following props:
className
– Can be used on any Clerk Elements component that renders markup.
asChild
– Can be used to change the rendered element entirely.
This guide will demonstrate multiple different styling approaches using the following basic sign-in flow as a starting point:
/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" >
< 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" >
< Clerk.Field name = "code" >
< Clerk.Label >Code</ Clerk.Label >
< Clerk.Input />
< Clerk.FieldError />
</ Clerk.Field >
< SignIn.Action submit >Verify</ SignIn.Action >
</ SignIn.Strategy >
</ SignIn.Step >
</ SignIn.Root >
)
}
If you are already using Tailwind CSS , no additional setup is required. Classes from Tailwind can be applied to most Clerk Elements components. Use your editor's IntelliSense to see if className
is a valid prop on a component you want to style.
/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"
className = "bg-white w-96 rounded-2xl py-10 px-8 shadow-sm border space-y-6"
>
< div className = "grid grid-cols-2 gap-x-4" >
< Clerk.Connection
name = "google"
className = "flex items-center gap-x-3 justify-center font-medium border shadow-sm py-1.5 px-2.5 rounded-md"
>
< Clerk.Icon className = "size-4" />
Google
</ Clerk.Connection >
< Clerk.Connection
name = "github"
className = "flex items-center gap-x-3 justify-center font-medium border shadow-sm py-1.5 px-2.5 rounded-md"
>
< Clerk.Icon className = "size-4" />
GitHub
</ Clerk.Connection >
</ div >
< Clerk.Field name = "identifier" className = "space-y-2" >
< Clerk.Label className = "text-sm font-medium" >Email</ Clerk.Label >
< Clerk.Input className = "w-full border rounded-md py-1.5 px-2.5" />
< Clerk.FieldError className = "block text-red-500 text-sm" />
</ Clerk.Field >
< SignIn.Action submit className = "bg-black text-white rounded-md py-1.5 px-2.5" >
Continue
</ SignIn.Action >
</ SignIn.Step >
</ SignIn.Root >
)
}
Many of the Clerk Elements components accept an asChild
prop that allows you to swap out the rendered element. This is useful if you have an existing design system or component library that you wish to use with Clerk Elements.
/app /sign-in /[[...sign-in]] /page.tsx 'use client'
import * as Clerk from '@clerk/elements/common'
import * as SignIn from '@clerk/elements/sign-in'
import { Button } from '@components/button'
import { Input } from '@components/input'
export default function SignInPage () {
return (
< SignIn.Root >
< SignIn.Step name = "start" >
< Clerk.Connection name = "google" asChild >
< Button >Sign in with Google</ Button >
</ Clerk.Connection >
< Clerk.Field name = "identifier" >
< Clerk.Label >Email</ Clerk.Label >
< Clerk.Input asChild >
< Input />
</ Clerk.Input >
< Clerk.FieldError />
</ Clerk.Field >
< SignIn.Action submit asChild >
< Button >Continue</ Button >
</ SignIn.Action >
</ SignIn.Step >
< SignIn.Step name = "verifications" >
< SignIn.Strategy name = "email_code" >
< Clerk.Field name = "code" >
< Clerk.Label >Code</ Clerk.Label >
< Clerk.Input asChild >
< Input />
</ Clerk.Input >
< Clerk.FieldError />
</ Clerk.Field >
< SignIn.Action submit asChild >
< Button >Continue</ Button >
</ SignIn.Action >
</ SignIn.Strategy >
</ SignIn.Step >
</ SignIn.Root >
)
}
Notice how the Clerk Elements components are wrapping the rendered <Input>
and <Button>
when asChild
is used. This ensures the underlying event handlers and necessary props are passed along automatically.
To use the asChild
prop, your component must spread its incoming props and return forwardRef()
. Here's an example of how you might implement a custom <Input />
component:
import { forwardRef } from 'react'
const CustomInput = forwardRef ( function CustomInput (props , forwardedRef) {
return < input ref = {forwardedRef} { ... props} className = "custom-class" />
})
Classes from an imported CSS module can be applied to most Clerk Elements components with className
.
/app /sign-in /[[...sign-in]] /page.tsx 'use client'
import * as Clerk from '@clerk/elements/common'
import * as SignIn from '@clerk/elements/sign-in'
import styles from './sign-in.module.css'
export default function SignInPage () {
return (
< SignIn.Root >
< SignIn.Step name = "start" className = { styles .startStep}>
< Clerk.Connection name = "google" className = { styles .provider}>
Sign in with Google
</ Clerk.Connection >
< Clerk.Field name = "identifier" >
< Clerk.Label className = { styles .label}>Email</ Clerk.Label >
< Clerk.Input className = { styles .input} />
< Clerk.FieldError className = { styles .error} />
</ Clerk.Field >
< SignIn.Action submit className = { styles .submit}>
Continue
</ SignIn.Action >
</ SignIn.Step >
< SignIn.Step name = "verifications" className = { styles .verificationsStep}>
< SignIn.Strategy name = "email_code" >
< Clerk.Field name = "code" >
< Clerk.Label className = { styles .label}>Code</ Clerk.Label >
< Clerk.Input className = { styles .input} />
< Clerk.FieldError className = { styles .error} />
</ Clerk.Field >
< SignIn.Action submit className = { styles .submit}>
Verify
</ SignIn.Action >
</ SignIn.Strategy >
</ SignIn.Step >
</ SignIn.Root >
)
}
You can also use inline styles with Clerk Elements. This is useful when you need to apply styles conditionally or avoid creating a separate CSS file.
/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"
style = {{
backgroundColor : 'white' ,
padding : '1rem' ,
border : '1px solid #dddddd' ,
borderRadius : '4px' ,
}}
>
< Clerk.Field name = "identifier" >
< Clerk.Label
style = {{
color : '#dddddd' ,
fontSize : '0.875rem' ,
}}
>
Email
</ Clerk.Label >
< Clerk.Input
style = {{
border : '1px solid #dddddd' ,
borderRadius : '4px' ,
padding : '1rem' ,
}}
/>
</ Clerk.Field >
< SignIn.Action
submit
style = {{
backgroundColor : '#111111' ,
color : 'white' ,
padding : '1rem' ,
borderRadius : '4px' ,
}}
>
Continue
</ SignIn.Action >
</ SignIn.Step >
</ SignIn.Root >
)
}
In some cases you might want to style components based on their state. Clerk Elements exposes data attributes for this purpose, as well as components that expose the state programmatically to support more complex logic.
<Field>
and <Input>
can be styled based on their validity state by targeting the data-valid
or data-invalid
attributes:
style.css .input {
--border-color : gray ;
border : 1 px solid var (--border-color) ;
&[ data-invalid ] {
--border-color : red ;
}
}
page.tsx < Clerk.Input className = "input" />
If you need programmatic access to state for more complex styling, several components accept a function as children. This is useful when dealing with animations, or for conditionally rendering elements based on state.
For example, to access a field's state, use <FieldState>
.
page.tsx < Clerk.Field name = "email" >
< Clerk.FieldState >{(state) => state === 'invalid' && < ErrorIcon />}</ Clerk.FieldState >
< Clerk.Label >Email</ Clerk.Label >
< Clerk.Input />
< Clerk.FieldError />
</ Clerk.Field >