Input OTP
Accessible one-time password input that renders individual character slots backed by a single hidden text field, with built-in digit filtering, separator groups, error state, and blinking caret.
InputOTP renders a row of character-slot boxes driven by a single invisible BasicTextField. The component automatically filters input to digits when keyboardType is numeric and trims the value to length. Each slot animates its border colour on focus, error, and blur transitions, and shows a blinking caret when it is the active slot. Separator groups can be inserted at arbitrary positions using separatorIndices.
Basic usage
With separator
Pass a Set<Int> of zero-based slot indices to separatorIndices. A separator is rendered after each listed index. The example below splits a 6-digit code into two groups of three.
The separator is not rendered after the last slot even if its index appears in
separatorIndices.
Custom length
Use length to control how many slots are displayed. Input beyond that length is silently trimmed by onValueChange.
Error state
Set isError = true to highlight all slot borders with the theme's destructive colour. Pair it with an error message below the field for full accessibility.
Disabled
Set enabled = false to prevent all interaction. The entire row is rendered at 50 % alpha.
API reference
InputOTP
| Parameter | Type | Default | Description |
|---|---|---|---|
value | String | — | Current OTP string. |
onValueChange | (String) -> Unit | — | Called with the filtered and length-trimmed new value. |
modifier | Modifier | Modifier | Applied to the root BasicTextField. |
length | Int | 6 | Number of character slots to render. |
enabled | Boolean | true | When false, disables interaction and renders at 50 % alpha. |
isError | Boolean | false | When true, slot borders switch to the destructive colour. |
keyboardType | KeyboardType | KeyboardType.NumberPassword | Soft-keyboard type. Numeric types automatically filter non-digit input. |
keyboardActions | KeyboardActions | KeyboardActions.Default | Callbacks for IME actions (e.g. onDone). |
separatorIndices | Set<Int> | emptySet() | Zero-based slot indices after which to render the separator. |
separator | @Composable () -> Unit | { InputOTPSeparator() } | Composable placed between slot groups. |
slotSize | Dp | InputOTPDefaults.SlotSize (40 dp) | Width and height of each square slot. |
colors | InputOTPStyle | InputOTPDefaults.colors() | Theme colours for the component. |
InputOTPDefaults
| Member | Description |
|---|---|
SlotSize: Dp | Default slot size — 40.dp. |
SlotGap: Dp | Gap between adjacent slots — 0.dp (slots are flush). |
GroupGap: Dp | Gap added on each side of a separator — 8.dp. |
colors(): InputOTPStyle | Returns the default theme-derived colour set. |
colors(overrides) | Accepts a lambda InputOTPStyle.() -> InputOTPStyle for partial overrides via copy(...). |
InputOTPStyle
| Field | Type | Description |
|---|---|---|
background | Color | Slot background. Defaults to Color.Unspecified (transparent). |
text | Color | Character text colour when enabled. |
disableText | Color | Character text colour when disabled. |
activeRing | Color | Semi-transparent ring drawn around the active slot (ring colour at 50 % alpha). |
caret | Color | Blinking caret colour in the active empty slot. |
border | InputOTPBorderStyle | Border colours for each slot state. |
InputOTPBorderStyle
| Field | Type | Description |
|---|---|---|
default | Color | Border colour when the slot is idle. |
focus | Color | Border colour of the active slot. |
error | Color | Border colour when isError = true. |