KQ-1322 · SIGN/IN

Sign In

An authentication card: email first under generic single sign-on buttons, then a choice of method, a code or a password slides in from 16px on glide while the card's height glides to the new step and the step pips widen on snap. The code is one real input drawn as cells — a ring slides on snap to the cell the next digit lands in, digits land on snap, a paste fills them all, and a full code verifies itself under a travelling wave — while a refused field shakes on a symmetric tween, never a spring, and an accepted sign-in flies the button that finished it into the welcome's avatar on glide. Every step is a real form: Enter submits, Escape goes back a step, and focus moves to each step's first field as it arrives.

KQ-1322 · SIGN/IN

Sign in to Fernworks

Welcome back. Use your work email.

New to Fernworks?

email · mara@fernworks.app

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/sign-in

Props

steps
"choose" | "code" | "password"
default "choose"
What follows the email: a choice of method, straight to an emailed code, or straight to a password.
shake
number
default 8
How far a refused field shakes, in px; 0 for no shake.
cells
number
default 6
How many digits the sign-in code has, 4 to 8.
brand
string
default "Fernworks"
The product's name, in the heading and the accessible name.
mark
React.ReactNode
default —
The product's mark, 32px. Defaults to the brand's initial on a tile.
providers
SignInProvider[]
default defaultSignInProviders
Single sign-on buttons above the email field, each with a label and an icon; an empty list hides them.
aside
SignInAside | null
default defaultSignInAside
The brand panel beside the form from 640px wide: heading, line, points, and a quote from 960px. Null for none.
email / defaultEmail
string
default ""
The email address. Controlled or uncontrolled.
onEmailChange
(email: string) => void
default —
Fires as the email is typed.
step / defaultStep
"email" | "method" | "code" | "password" | "welcome"
default "email"
The step on show. Controlled or uncontrolled.
onStepChange
(step: SignInStep) => void
default —
Fires from the press or key that moved the flow, before the new step shows.
onEmailSubmit
(email: string) => void | Promise<void>
default —
Checks the email before the next step; reject with an Error to refuse it with your message.
onSendCode
(email: string) => void | Promise<void>
default —
Sends the code and its link; called again by Resend.
onVerifyCode
(email: string, code: string) => void | Promise<SignInAccount | void>
default —
Checks a complete code. Reject to refuse it; resolve with the account to welcome it by name.
onVerifyPassword
(email: string, password: string) => void | Promise<SignInAccount | void>
default —
Checks a password, the same way.
onProvider
(providerId: string) => void | Promise<SignInAccount | void>
default —
Runs a single sign-on button, the same way.
onSuccess
(account: SignInAccount) => void
default —
Fires the moment a sign-in is accepted, with the account.
onForgotPassword
(email: string) => void
default —
The Forgot password link on the password step.
onCreateAccount
() => void
default —
The Create an account link under the email step.
sound
boolean
default false
Play a click on presses, a buzz on a refusal and a chime as the welcome lands. Off unless asked for.
disabled
boolean
default false
Shows the card but takes no input.
label
string
default —
The group's accessible name. Defaults to "Sign in to" and the brand.
className
string
default —
Classes for the root. The card is content-sized and lays itself out by its own width.