VI Controls

Star on GitHubFeedback
VI ControlsNative HTML and a hookot-code

Input OTP

A one-time code on short baselines, three and three. Digits drop in as you type; whole, the lines ink in turn. Or the code closes up into one figure, or is read back in words under its digits.

Report an issue with Input OTP

Example

For this page, the code is 246810.

For this page, the code is 246810.

For this page, the code is 246810.

Waiting
Whole
Wrong
close-up, waiting
close-up, whole
close-up, wrong
lyric, waiting
lyric, whole

Install

Run it in a project that has the shadcn CLI set up. It brings the 0nlyType base and field along.

npx shadcn@latest add https://thedirectors.agency/ui/r/input-otp.json

Usage

input-otp-example.tsx
"use client"import * as React from "react"import { Field } from "@/components/ui/field"import { InputOTP, type InputOTPProps } from "@/components/ui/input-otp"// For this page, the code we sent is 246810.function Check({ label, variant }: { label: string; variant?: InputOTPProps["variant"] }) {const [error, setError] = React.useState<string>()return (<Field label={label} hint="For this page, the code is 246810." error={error} className="max-w-md"><InputOTPvariant={variant}onValueChange={() => setError(undefined)}onComplete={(code) => code !== "246810" && setError("That code doesn't match. Check the message and type it again.")}/></Field>)}export default function Example() {return (<div className="grid gap-12"><Check label="The code we sent to your phone" /><Check label="The code from your email" variant="close-up" /><Check label="The code we read to you" variant="lyric" /></div>)}

Contract

  • Underneath: native input, plus a hook.
  • Anatomy: <div class="ot-code"> holding one <input inputmode="numeric" autocomplete="one-time-code" maxlength="6"> and six .ot-code-slot spans split three and three by .ot-code-sep, a leaning hairline. Script copies the digits into the slots and sets data-here on the next slot and data-state="done | wrong" on the box.
  • Each digit drops onto its baseline in italic (ot-drop-in); the waiting line is the accent. Whole, the lines ink in turn. Wrong, they turn crimson together and an ot-field-error says why.
  • One real input underneath, so paste, autofill and the keyboard all work natively.
  • Variant close-up (the proofreader's close-up mark; the tight tracking of "the uncreative"): a dot waits for each digit, the next one in the accent. Whole, the spaces close and the halves meet in one tight figure; the mark's two arcs land over and under the join. Wrong, the spaces open again in crimson.
  • Variant lyric (the score's lyric line; a cheque's sum in words): each digit is read back in words under its line (.ot-code-word, ours, upright), with a comma at the halfway breath and a full stop at the end, so the code can be checked aloud against the message. Whole, the words ink.

Props

Props of Input OTP
PropTypeDefaultWhat it does
variant"line" | "close-up" | "lyric""line"How the code waits and ends. line: short baselines, three and three; whole, they ink in turn. close-up: a dot waits for each digit, the next in the accent; whole, the spaces close into one tight figure and the proofreader's close-up mark lands over and under the join. lyric: each digit is read back in words under its line, as lyrics sit under their notes, with a comma at the halfway breath and a full stop at the end, so the code can be checked aloud.
lengthnumber6How many digits.
groupnumberA separator stands after every this many slots. Three and three for six.
value / defaultValue / onValueChangestringThe digits typed so far. Anything that isn't a digit is dropped.
onComplete(value: string) => voidCalled once, when the last slot fills.
aria-invalidbooleanWhole and wrong, the lines turn crimson together. Inside a Field with an error this is set for you.

Craft

Where its move comes from

Where its move comes from
ComponentReferenceMove
One-time code"Less is more." rulesShort baselines, three and three
Close-up codeThe proofreader's close-up mark; "the uncreative"Dots wait; whole, the code closes into one figure
Lyric codeThe score's lyric line; a cheque's sum in wordsEach digit read back in words under it

How it moves

How it moves
ComponentArticulationWhat moves
One-time codeDropEach digit drops onto its line; whole, the lines ink in turn
Close-up codeClose upWhole, the spaces close; the two arcs land over and under the join
Lyric codeRead backEach word opens from its middle under its digit