Stable in React
OTP Field
A one-time password input made of single-character slots.
Install#
One package per framework. OTP Field's parts come from it; the anatomy tab at the top shows how they nest.
bun add @▢▢▢▢/reactThree parts. The example uses three of them; the data does not say which are required.
OTPField.RootGroups all OTP field parts and manages their state.OTPField.SeparatorA separator element accessible to screen readers.OTPField.InputAn individual OTP character input.
Examples#
Common ways to put it to work. Each one runs live.
validationType accepts letters and digits for recovery or invite codes.
OTPFieldAlphanumeric.tsxStyling and accessibility#
The parts ship no styles. Style their states with these attributes; the CSS tab at the top has a sheet. The same CSS works in all five frameworks.
[data-complete]Present when all slots are filled. On Root, Input.[data-disabled]Present when the OTP field is disabled. On Root, Input.[data-readonly]Present when the OTP field is readonly. On Root, Input.[data-required]Present when the OTP field is required. On Root, Input.[data-valid]Present when the OTP field is in a valid state (when wrapped in Field.Root). On Root, Input.[data-invalid]Present when the OTP field is in an invalid state (when wrapped in Field.Root). On Root, Input.[data-touched]Present when the OTP field has been touched (when wrapped in Field.Root). On Root, Input.[data-dirty]Present when the OTP field's value has changed (when wrapped in Field.Root). On Root, Input.[data-filled]Present when the OTP field contains at least one character. On Root, Input.[data-focused]Present when one of the OTP field inputs is focused. On Root, Input.[data-orientation]Indicates the orientation of the separator. On Separator.
Keyboard
- Fills the slot and moves to the next one On Input.
- ArrowLeftArrowRightMoves between slots On Input.
- HomeMoves to the first slot On Input.
- EndMoves to the first empty slot at the end On Input.
- BackspaceDeletes the character and moves to the previous slot On Input.
- DeleteDeletes the character and stays in the slot On Input.
Set for you
the slots are read as one named fieldRootrole="group",aria-labelledbyto the Field labeltabindex="0"on the active slot onlyTabpasses the whole code in one stepInputthe field's label on the first slot, youreach slot can be named, such as "Character 2 of 6"Inputaria-labelon the othersthe error state is read on every slotInputaria-invalidwhen validation failsa visual break between groups of slots is announced as suchSeparatorrole="separator"
API reference#
19 props across 3 parts, in React syntax, and className, style, render once for every part. Open a row to try it.
OTPField · all partsclassNameCSS class applied to the element, or a function that
returns a class based on the component's state.string | ((state: State) => string | undefined)styleStyle applied to the element, or a function that
returns a style object based on the component's state.React.CSSProperties | ((state: State) => React.CSSProperties | undefined)renderAllows you to replace the component's HTML element
with a different tag, or compose it with another component.React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, State>Use it in React#
What differs from the React API. Switch the framework at the top of the page.
@▢▢▢▢/react is the React 19 package. Its parts, props, data attributes and error messages are upstream Base UI's, and upstream's own tests run against it.
- Parts
Each component is its own entry point and exports one namespace named after it.
import { Switch } from '@base-ui-next/react/switch' export function Example() { return ( <Switch.Root> <Switch.Thumb /> </Switch.Root> ) }A part renders the element its API reference names, such as a
<span>forSwitch.Root. - Props and events
Props and callbacks have upstream's names and signatures:
onCheckedChange(checked, details),onOpenChange(open, details),onValueChange(value, details).detailscarriesreason,event,cancel()andallowPropagation(). Native handlers are React's (onClick,onKeyDown), andevent.preventBaseUIHandler()stops a part's own handler. - Styling
classNametakes a string or a function(state) => string;styletakes an object or a function(state) => object. The state'sdata-*attributes are on the element for CSS. renderrendertakes an element (render={<a href="/docs" />}) or a function(props, state) => elementthat spreadspropson what it returns.- Refs
refreaches the part's element. Imperative handles are ref props, as upstream:inputRef, andactionsRef({ validate }on Field and Form,{ unmount, close }on Dialog). - Binding
A part is controlled when its value prop (
checked,open,value) is set, and uncontrolled with thedefaultform (defaultChecked,defaultOpen,defaultValue). React has no two-way binding: pair the value with its change callback. - From @base-ui/reactChange the import from
@base-ui/react/<component>to@▢▢▢▢/react/<component>. - From @base-ui/reactNothing else changes: props, parts, data attributes and errors are the same.