Install
Pull Input OTP from the barrel for everyday use, or the granular path when you want a tighter bundle.
import { InputOTP } from "@brika/clay";import { InputOTP } from "@brika/clay/components/input-otp";A minimal example
Drop this into a page. Native HTML attributes pass through to the underlying primitive.
'use client';
import {
InputOTP,
InputOTPGroup,
InputOTPSeparator,
InputOTPSlot,
} from '@brika/clay/components/input-otp';
/** Six-digit OTP split into two groups of three with a dash separator. */
export default function InputOTPDefaultDemo() {
return (
<InputOTP maxLength={6}>
<InputOTPGroup>
<InputOTPSlot index={0} />
<InputOTPSlot index={1} />
<InputOTPSlot index={2} />
</InputOTPGroup>
<InputOTPSeparator />
<InputOTPGroup>
<InputOTPSlot index={3} />
<InputOTPSlot index={4} />
<InputOTPSlot index={5} />
</InputOTPGroup>
</InputOTP>
);
}Input OTP, every way
Controlled
Controlled OTP that shows a Verify button only once all six slots are filled.
Numeric
Digits-only input using the REGEXP_ONLY_DIGITS pattern, rejects letters and symbols.
Pattern
Four-slot PIN entry without a separator, suitable for numeric PINs.
Placeholder
Muted dot placeholder in each empty slot, fades out on focus or fill.
Accessibility
- Paste works out-of-the-box, pasting a code fills all slots.
- A single hidden
<input>handles the value; each visible slot is a presentation of that input's characters. - The active slot gets a focus ring matching the input's focus state.
- Numeric-only patterns should use
inputMode="numeric"to bring up the numeric keyboard on mobile.
Theme tokens
Every CSS variable Input OTP reads, with its default and the
dotted path you'd write in a ThemeConfig JSON
to override it. Set any of these in your theme to retune Input OTP
without touching component code.
Input OTP tokens
22 tokens--input-otp-containercolorvar(--input-container)components.inputOtp.containerBackground color of each OTP slot in its resting state.
--input-otp-bordercolorvar(--input-border)components.inputOtp.borderBorder color of each OTP slot in its resting state.
--input-otp-labelcolorvar(--foreground)components.inputOtp.labelForeground color of the entered character rendered inside an OTP slot.
--input-otp-focus-bordercolorvar(--ring)components.inputOtp.focusBorderBorder color of the active OTP slot (`data-active=true`).
--input-otp-focus-ringcolorvar(--ring)components.inputOtp.focusRingColor of the 3px focus halo painted around the active OTP slot. Rendered at 50% opacity to soften the outer glow.
--input-otp-invalid-ringcolorvar(--destructive)components.inputOtp.invalidRingSingle color driving the invalid state on an OTP slot: the border uses it directly while the surrounding ring uses it at 20% opacity.
--input-otp-placeholder-colorcolorvar(--muted-foreground)components.inputOtp.placeholderColorFill color of the placeholder dot rendered in an empty, non-focused OTP slot. Applied at 40% opacity in the rendered output.
--input-otp-caret-colorcolorvar(--foreground)components.inputOtp.caretColorColor of the blinking fake caret rendered inside the active OTP slot.
--input-otp-separator-colorcolorvar(--muted-foreground)components.inputOtp.separatorColorColor of the minus icon used as a visual separator between OTP groups.
--input-otp-sizesize2.5remcomponents.inputOtp.sizeOTP slot width and height.
--input-otp-radiusradiusvar(--radius-control)components.inputOtp.radiusOTP slot corner radius.
--input-otp-border-widthborder-width1pxcomponents.inputOtp.borderWidthBorder width on the input-otp. Set non-zero for outline-style variants.
--input-otp-border-styleborder-stylesolidcomponents.inputOtp.borderStyleBorder style on the input-otp (`solid`, `dashed`, `double`, `none`).
--input-otp-font-familyfont-familyvar(--font-sans)components.inputOtp.fontFamilyTypeface for input-otp.
--input-otp-font-sizefont-sizevar(--text-body-md)components.inputOtp.fontSizeFont size for input-otp.
--input-otp-font-weightfont-weight500components.inputOtp.fontWeightFont weight for input-otp.
--input-otp-line-heightline-height1.25components.inputOtp.lineHeightLine height for input-otp.
--input-otp-letter-spacingletter-spacing0components.inputOtp.letterSpacingLetter spacing for input-otp. Useful for caps labels.
--input-otp-text-transformtext-transformnonecomponents.inputOtp.textTransformText transform for input-otp (`uppercase`, `lowercase`, `capitalize`, `none`).
--input-otp-backdrop-blurblur0pxcomponents.inputOtp.backdropBlurBackdrop blur applied to the input-otp slot surface. Set non-zero for a frosted-glass treatment.
--input-otp-durationdurationvar(--motion-standard-duration)components.inputOtp.durationTransition duration for input-otp state changes.
--input-otp-easingeasingvar(--motion-standard-easing)components.inputOtp.easingTransition easing for input-otp state changes.
Override in a theme
Authoring a theme is plain JSON. Drop overrides under
components.inputOtp, the names
are camelCase versions of the variable suffix.
{
"id": "my-theme",
"name": "My Theme",
"description": "...",
"accentSwatches": ["#000"],
"components": {
"inputOtp": {
"radius": "var(--radius-control)"
}
}
}
Then apply with applyTheme(myTheme)
(see the theming guide),
scope it to a subtree with themeToCssVars(myTheme, mode),
or consume any token directly in your own JSX with the matching Tailwind utility
(e.g. bg-input-otp-…) — see the
chips on each token row.
API reference
Props specific to Input OTP. Native HTML attributes pass through to the underlying primitive, see the component source on GitHub for the full type signature.
<InputOTP />
1 prop- string
No description.
<InputOTPGroup />
passthroughNo wrapper-specific props, all attributes pass through to the underlying primitive.
<InputOTPSeparator />
passthroughNo wrapper-specific props, all attributes pass through to the underlying primitive.
<InputOTPSlot />
2 props- number
No description.
- placeholderdefault
falsebooleanRender a muted dot in the centre of the slot while it's empty and not focused. Disappears as soon as the slot has a value or becomes the active slot (where the caret takes over).