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