For an ordinary short text or number take CdsTextInput:
CdsOtpInputis needed where the length of the input is known upfront and every character is shown in its own cell.
Anatomy
The cells (CdsOtpField) only draw the code — the entered character, the placeholder or the blinking caret. The real input is taken by a hidden input: it is pressed to the bottom edge of the component, so the SMS autofill suggestion appears under the cells and covers nothing. A separator (CdsOtpSeparator) may stand between the cells, and in the merged look the cells are gathered into a group (CdsOtpGroup).
Variations
Length and type of the code
The length prop sets the number of cells, type — what may be entered: number (the default) accepts digits only and opens the numeric keyboard on mobile, text — any characters, password additionally hides what is entered behind dots. The same effect without changing the type is given by masked.
Allowed characters
The pattern prop narrows the set of characters: the name of a ready set (numeric, alpha, alphanumeric, unicode-alpha, unicode-alphanumeric) or your own regular expression. The check goes character by character — the extra ones will not get into the field, neither from the keyboard nor from the clipboard.
Separator
The divider prop puts a character between the cells — a hyphen in a code like 123-456, for example. The divider slot gives full freedom of markup and receives index — the number of the cell to the left of the separator, so the separator can be placed only where it is needed.
Merged look
The merged prop removes the gaps: the cells become a single field with a common border. This look is more compact and breaks the form up less.
Placeholder
The placeholder prop shows a character in the empty cells — a hint about the format or simply a dot, so that the row does not look empty.
Sizes
The size prop changes the height of the cells and the font size. The default size is md.
States
disabled blocks the input, error highlights the whole row with the error color, loading shows an indicator on top of the cells and does not erase the entered code. focus-all highlights the whole row while the field is focused, not just the active cell.
Slots
| Slot | Description |
|---|---|
fields | The whole row of cells — your own markup of CdsOtpGroup, CdsOtpField and CdsOtpSeparator |
divider | The separator between the cells, index is the number of the cell to its left |
loader | Your own loading indicator (with loading) |
default | Arbitrary content on top of the cells |
The fields slot is needed when the cells are gathered into groups: every CdsOtpField receives its own index, and CdsOtpGroup joins the neighboring cells into a common border.
Guidelines
Scenarios
Confirmation by SMS
The finish event fires as soon as the whole code is entered — send the request on it, a separate button is not needed. Turn on loading for the duration of the check: the code stays on the screen and the field does not look broken. If the server did not accept the code, error highlights the row, and the reset() and focus() methods called through a ref clear the field and bring the cursor back into it.
Resending the code
The "Send again" button opens on a timer — that way the user does not flood the gateway with requests. Reset the field together with the new code: reset() clears the cells, focus() puts the cursor into the first one, and the old code does not mix with the new one.
A code inside a form
When the code is a part of the sign-in form, keep the confirmation button: it gives an explicit moment of submission. The button waits until all the characters are entered — the length of the code is visible from v-model, and disabled on the field freezes the code that has already been confirmed.
API
CdsOtpInput
Props
| Name | Type | Default | Description |
|---|---|---|---|
activeColor | string | undefined | — | Color of the component in its active state |
autofocus | boolean | undefined | — | Enables autofocus |
baseColor | string | undefined | — | Color of the component in its inactive state |
bgColor | string | undefined | — | Background color of the component |
color | string | undefined | — | Component color |
disabled | boolean | null | undefined | null | Disabled state |
divider | string | undefined | — | Separator character placed between the code cells |
error | boolean | undefined | — | Error state |
focusAll | boolean | undefined | — | Highlight all the cells while the field is focused, not only the active one |
focused | boolean | undefined | — | Controls the focus state of the component. When true, the component is considered focused and may apply the corresponding styles or behavior. |
height | string | number | undefined | — | Component height |
label | string | undefined | '$cds.input.otp' | Accessible name of the field (aria-label). Accepts a localization key such as $cds.input.otp |
length | string | number | undefined | 6 | Number of code cells |
loading | string | boolean | undefined | — | Loading indicator for the component |
masked | boolean | undefined | — | Hide the entered characters behind dots |
maxHeight | string | number | undefined | — | Maximum component height |
maxWidth | string | number | undefined | — | Maximum component width |
merged | boolean | undefined | — | Merged look: the cells are joined into a single field with no gaps between them |
minHeight | string | number | undefined | — | Minimum component height |
minWidth | string | number | undefined | — | Minimum component width |
modelValue | string | number | undefined | — | Value of the component (v-model) |
pattern | RegExp | "numeric" | "alpha" | "alphanumeric" | "unicode-alpha" | "unicode-alphanumeric" | undefined | — | Allowed characters: the name of a ready pattern (numeric, alpha, alphanumeric, unicode-alpha, unicode-alphanumeric) or your own regular expression |
placeholder | string | undefined | — | Placeholder character shown in an empty cell |
size | number | "xs" | "sm" | "md" | "lg" | "xl" | undefined | 'md' | Size of the component |
textColor | string | undefined | — | Text color of the component |
theme | string | undefined | — | Component theme |
type | CdsOtpInputType | undefined | 'number' | Type of the code being entered. number limits the input to digits, password hides the characters |
width | string | number | undefined | — | Component width |
Events
| Name | Type | Description |
|---|---|---|
finish | [value: string] | Fires when the whole code has been entered |
update:focused | [focused: boolean] | Fires when the field gains or loses focus |
update:modelValue | [value: string] | Fires when the value of the component changes |
Slots
| Name | Type | Description |
|---|---|---|
default | any | Arbitrary content on top of the code cells |
divider | { index: number; } | Separator between the cells. index is the number of the cell to the left of it |
fields | any | Fully replaces the row of cells with your own markup made of CdsOtpGroup, CdsOtpField and CdsOtpSeparator |
loader | any | Custom loading indicator |
Exposed
| Name | Type | Description |
|---|---|---|
blur | () => void | Remove the focus from the field |
focus | () => void | Set the focus on the field |
inputRef | HTMLInputElement | undefined | Ref to the hidden input that receives the code |
isFocused | boolean | undefined | Focus state of the field |
reset | () => void | Clear the entered code |
CdsOtpField
Props
| Name | Type | Default | Description |
|---|---|---|---|
index* | number | — | Zero-based index of the cell |
CdsOtpGroup
Props
| Name | Type | Default | Description |
|---|---|---|---|
merged | boolean | null | undefined | null | Merged look of the group. Inherited from the parent CdsOtpInput by default |
Slots
| Name | Type | Description |
|---|---|---|
default | any | The code cells of the group |
CdsOtpSeparator
Slots
| Name | Type | Description |
|---|---|---|
default | any | Content of the separator |