Skip to content

PinInput

Controlled multi-cell input for one-time codes, PINs, and short verification codes.

Verification code
function ControlledPinInput({
isOptional,
isRequired,
value: initialValue = '',
...props
}: ControlledPinInputProps): React.JSX.Element {
const [value, setValue] = useState(initialValue);
return (
<PinInput
{...props}
{...getNecessity(isOptional, isRequired)}
onChange={setValue}
value={value}
/>
);
}
<ControlledPinInput {...args} />
Four-digit PIN
function ControlledPinInput({
isOptional,
isRequired,
value: initialValue = '',
...props
}: ControlledPinInputProps): React.JSX.Element {
const [value, setValue] = useState(initialValue);
return (
<PinInput
{...props}
{...getNecessity(isOptional, isRequired)}
onChange={setValue}
value={value}
/>
);
}
<ControlledPinInput {...args} />
Recovery code
function ControlledPinInput({
isOptional,
isRequired,
value: initialValue = '',
...props
}: ControlledPinInputProps): React.JSX.Element {
const [value, setValue] = useState(initialValue);
return (
<PinInput
{...props}
{...getNecessity(isOptional, isRequired)}
onChange={setValue}
value={value}
/>
);
}
<ControlledPinInput {...args} />
Secret PIN
function ControlledPinInput({
isOptional,
isRequired,
value: initialValue = '',
...props
}: ControlledPinInputProps): React.JSX.Element {
const [value, setValue] = useState(initialValue);
return (
<PinInput
{...props}
{...getNecessity(isOptional, isRequired)}
onChange={setValue}
value={value}
/>
);
}
<ControlledPinInput {...args} />
Small code
Medium code
Large code
function ControlledPinInput({
isOptional,
isRequired,
value: initialValue = '',
...props
}: ControlledPinInputProps): React.JSX.Element {
const [value, setValue] = useState(initialValue);
return (
<PinInput
{...props}
{...getNecessity(isOptional, isRequired)}
onChange={setValue}
value={value}
/>
);
}
<div style={{display: 'flex', flexDirection: 'column', gap: 16}}>
<ControlledPinInput label="Small code" size="sm" />
<ControlledPinInput label="Medium code" size="md" />
<ControlledPinInput label="Large code" size="lg" />
</div>
Verification code
function ControlledPinInput({
isOptional,
isRequired,
value: initialValue = '',
...props
}: ControlledPinInputProps): React.JSX.Element {
const [value, setValue] = useState(initialValue);
return (
<PinInput
{...props}
{...getNecessity(isOptional, isRequired)}
onChange={setValue}
value={value}
/>
);
}
<ControlledPinInput {...args} />
Verification codeRequired
function ControlledPinInput({
isOptional,
isRequired,
value: initialValue = '',
...props
}: ControlledPinInputProps): React.JSX.Element {
const [value, setValue] = useState(initialValue);
return (
<PinInput
{...props}
{...getNecessity(isOptional, isRequired)}
onChange={setValue}
value={value}
/>
);
}
<ControlledPinInput {...args} />
Verification codeEnter the code sent to your phone.
function ControlledPinInput({
isOptional,
isRequired,
value: initialValue = '',
...props
}: ControlledPinInputProps): React.JSX.Element {
const [value, setValue] = useState(initialValue);
return (
<PinInput
{...props}
{...getNecessity(isOptional, isRequired)}
onChange={setValue}
value={value}
/>
);
}
<ControlledPinInput {...args} />
Verification code
function ControlledPinInput({
isOptional,
isRequired,
value: initialValue = '',
...props
}: ControlledPinInputProps): React.JSX.Element {
const [value, setValue] = useState(initialValue);
return (
<PinInput
{...props}
{...getNecessity(isOptional, isRequired)}
onChange={setValue}
value={value}
/>
);
}
<ControlledPinInput {...args} />
Large authentication control
OTP
Invalid authentication control
OTP
Disabled authentication control
OTP
function ControlledPinInput({
isOptional,
isRequired,
value: initialValue = '',
...props
}: ControlledPinInputProps): React.JSX.Element {
const [value, setValue] = useState(initialValue);
return (
<PinInput
{...props}
{...getNecessity(isOptional, isRequired)}
onChange={setValue}
value={value}
/>
);
}
<div style={{display: 'flex', flexDirection: 'column', gap: 16}}>
<InputGroup label="Large authentication control" size="lg">
<InputGroupText>OTP</InputGroupText>
<ControlledPinInput label="Verification code" size="sm" />
</InputGroup>
<InputGroup
label="Invalid authentication control"
status={{message: 'Check the supplied code.', type: 'error'}}>
<InputGroupText>OTP</InputGroupText>
<ControlledPinInput label="Verification code" />
</InputGroup>
<InputGroup isDisabled label="Disabled authentication control">
<InputGroupText>OTP</InputGroupText>
<ControlledPinInput label="Verification code" />
</InputGroup>
</div>
Verification code
function ControlledPinInput({
isOptional,
isRequired,
value: initialValue = '',
...props
}: ControlledPinInputProps): React.JSX.Element {
const [value, setValue] = useState(initialValue);
return (
<PinInput
{...props}
{...getNecessity(isOptional, isRequired)}
onChange={setValue}
value={value}
/>
);
}
<ControlledPinInput {...args} />

Controlled multi-cell input for one-time codes, PINs, and short verification codes.

When isOptional: false, isRequired: false

PropTypeDefaultDescription
classNamestringAdditional CSS class names applied to the field root, or to the input wrapper when the input is inside an InputGroup.
data-testidstringTest ID applied to the input wrapper.
descriptionReactNodeSupporting text rendered below the label.
hasAutoFocusbooleanfalseWhether to focus the first empty cell on mount.
hasMaskbooleanfalseWhether to obscure the code's characters.
htmlNamestringHTML name attribute for the joined hidden form input.
isDisabledbooleanfalseWhether the input is disabled.
isReadOnlybooleanfalseWhether the value is displayed without allowing focus or interaction.
isLabelHiddenbooleanfalseWhether to visually hide the label.
label*stringField label.
labelIconIconComponentIcon shown before the label.
labelTooltipReactNodeTooltip shown beside the label.
lengthnumber6Number of code cells.
onBlur(event: FocusEvent<HTMLInputElement>) => voidCalled when focus leaves the input's cells. Moving between cells does not trigger it.
onChange*( value: string, event: ChangeEvent<HTMLInputElement> | null, ) => voidCalled with the next joined value.
onComplete(value: string) => voidCalled when an edit transitions the code from incomplete to complete.
onFocus(event: FocusEvent<HTMLInputElement>) => voidCalled when focus enters the input's cells. Moving between cells does not trigger it.
refRef<HTMLDivElement>Ref forwarded to the component's outermost element.
size"sm" | "md" | "lg"'md'Visual size.
statusInputStatusValidation status displayed below the input.
styleCSSPropertiesInline styles applied to the field root, or to the input wrapper when the input is inside an InputGroup.
type"numeric" | "alphanumeric"'numeric'Characters accepted from user input.
value*stringControlled joined code value. Characters outside the set accepted by type are ignored.
isOptionalfalse
isRequiredfalse

When isOptional: true, isRequired: false

PropTypeDefaultDescription
classNamestringAdditional CSS class names applied to the field root, or to the input wrapper when the input is inside an InputGroup.
data-testidstringTest ID applied to the input wrapper.
descriptionReactNodeSupporting text rendered below the label.
hasAutoFocusbooleanfalseWhether to focus the first empty cell on mount.
hasMaskbooleanfalseWhether to obscure the code's characters.
htmlNamestringHTML name attribute for the joined hidden form input.
isDisabledbooleanfalseWhether the input is disabled.
isReadOnlybooleanfalseWhether the value is displayed without allowing focus or interaction.
isLabelHiddenbooleanfalseWhether to visually hide the label.
label*stringField label.
labelIconIconComponentIcon shown before the label.
labelTooltipReactNodeTooltip shown beside the label.
lengthnumber6Number of code cells.
onBlur(event: FocusEvent<HTMLInputElement>) => voidCalled when focus leaves the input's cells. Moving between cells does not trigger it.
onChange*( value: string, event: ChangeEvent<HTMLInputElement> | null, ) => voidCalled with the next joined value.
onComplete(value: string) => voidCalled when an edit transitions the code from incomplete to complete.
onFocus(event: FocusEvent<HTMLInputElement>) => voidCalled when focus enters the input's cells. Moving between cells does not trigger it.
refRef<HTMLDivElement>Ref forwarded to the component's outermost element.
size"sm" | "md" | "lg"'md'Visual size.
statusInputStatusValidation status displayed below the input.
styleCSSPropertiesInline styles applied to the field root, or to the input wrapper when the input is inside an InputGroup.
type"numeric" | "alphanumeric"'numeric'Characters accepted from user input.
value*stringControlled joined code value. Characters outside the set accepted by type are ignored.
isOptional*true
isRequiredfalse

When isOptional: false, isRequired: true

PropTypeDefaultDescription
classNamestringAdditional CSS class names applied to the field root, or to the input wrapper when the input is inside an InputGroup.
data-testidstringTest ID applied to the input wrapper.
descriptionReactNodeSupporting text rendered below the label.
hasAutoFocusbooleanfalseWhether to focus the first empty cell on mount.
hasMaskbooleanfalseWhether to obscure the code's characters.
htmlNamestringHTML name attribute for the joined hidden form input.
isDisabledbooleanfalseWhether the input is disabled.
isReadOnlybooleanfalseWhether the value is displayed without allowing focus or interaction.
isLabelHiddenbooleanfalseWhether to visually hide the label.
label*stringField label.
labelIconIconComponentIcon shown before the label.
labelTooltipReactNodeTooltip shown beside the label.
lengthnumber6Number of code cells.
onBlur(event: FocusEvent<HTMLInputElement>) => voidCalled when focus leaves the input's cells. Moving between cells does not trigger it.
onChange*( value: string, event: ChangeEvent<HTMLInputElement> | null, ) => voidCalled with the next joined value.
onComplete(value: string) => voidCalled when an edit transitions the code from incomplete to complete.
onFocus(event: FocusEvent<HTMLInputElement>) => voidCalled when focus enters the input's cells. Moving between cells does not trigger it.
refRef<HTMLDivElement>Ref forwarded to the component's outermost element.
size"sm" | "md" | "lg"'md'Visual size.
statusInputStatusValidation status displayed below the input.
styleCSSPropertiesInline styles applied to the field root, or to the input wrapper when the input is inside an InputGroup.
type"numeric" | "alphanumeric"'numeric'Characters accepted from user input.
value*stringControlled joined code value. Characters outside the set accepted by type are ignored.
isOptionalfalse
isRequired*true