We sent a code to your email.
<PinField.Root
size="sm"
variant="outline"
>
<PinField.Label>Verification code</PinField.Label>
<PinField.Input name="playground-code" />
<PinField.HelperText>We sent a code to your email.</PinField.HelperText>
<PinField.ErrorMessage>That code is incorrect.</PinField.ErrorMessage>
</PinField.Root>Features
- Supports numeric, alphabetic, and alphanumeric codes.
- Supports configurable code lengths and responsive sizes.
- Offers outline and fill variants with helper and error messages.
- Accepts pasted codes and one-time-code autofill.
- Supports controlled values, native form submission, and uncontrolled form reset.
Anatomy
<PinField.Root>
<PinField.Label>Verification code</PinField.Label>
<PinField.Input name="code" />
<PinField.HelperText>We sent a code to your email.</PinField.HelperText>
<PinField.ErrorMessage>That code is incorrect.</PinField.ErrorMessage>
</PinField.Root>Component Part
Description
Links the label and messages to the input, and shares size and state.
Names the code input.
Displays one cell per character and submits the code under its name.
Adds supporting text below the cells.
Explains the error while the root error state is set.
Sizes
import { PinField, Stack } from "@vortexlabs/vortex";
<Stack gap={6}>
<PinField.Root size="sm">
<PinField.Label>Small</PinField.Label>
<PinField.Input name="small-code" />
</PinField.Root>
<PinField.Root size="md">
<PinField.Label>Medium</PinField.Label>
<PinField.Input name="medium-code" />
</PinField.Root>
<PinField.Root size="lg">
<PinField.Label>Large</PinField.Label>
<PinField.Input name="large-code" />
</PinField.Root>
</Stack>Responsive Size
<PinField.Root size={{ xs: "sm", md: "lg" }} gap={{ xs: 2, md: 3 }}>
<PinField.Label>Verification code</PinField.Label>
<PinField.Input name="responsive-code" />
</PinField.Root>Variants
<Stack gap={6}>
<PinField.Root variant="outline">
<PinField.Label>Outline</PinField.Label>
<PinField.Input name="outline-code" />
</PinField.Root>
<PinField.Root variant="fill">
<PinField.Label>Fill</PinField.Label>
<PinField.Input name="fill-code" />
</PinField.Root>
</Stack>Length
Set length to the number of characters in the code. The default is 4.
<PinField.Root>
<PinField.Label>Six-digit code</PinField.Label>
<PinField.Input name="six-digit-code" length={6} />
</PinField.Root>Character Patterns
Use pattern="alphabetic" for letters or pattern="alphanumeric" for letters and digits. The default is numeric.
<Stack gap={6}>
<PinField.Root>
<PinField.Label>Digits only</PinField.Label>
<PinField.Input name="numeric-code" pattern="numeric" />
</PinField.Root>
<PinField.Root>
<PinField.Label>Letters only</PinField.Label>
<PinField.Input name="alphabetic-code" pattern="alphabetic" />
</PinField.Root>
<PinField.Root>
<PinField.Label>Letters and digits</PinField.Label>
<PinField.Input name="alphanumeric-code" pattern="alphanumeric" />
</PinField.Root>
</Stack>Disabled and Error States
Set error on PinField.Root to show PinField.ErrorMessage. Set disabled to prevent editing.
That code is incorrect.
<Stack gap={6}>
<PinField.Root error>
<PinField.Label>Verification code</PinField.Label>
<PinField.Input name="error-code" defaultValue="12" />
<PinField.ErrorMessage>That code is incorrect.</PinField.ErrorMessage>
</PinField.Root>
<PinField.Root disabled>
<PinField.Label>Unavailable code</PinField.Label>
<PinField.Input name="disabled-code" defaultValue="12" />
</PinField.Root>
</Stack>Controlled State
Set value and update it in onChange to control the code from your application.
Value: ""
"use client";
import { Button, PinField, Stack, Text } from "@vortexlabs/vortex";
import { useState } from "react";
export const PinFieldControlledExample = () => {
const [value, setValue] = useState("");
return (
<Stack gap={3}>
<Stack direction="row" gap={2}>
<Button size="xs" variant="secondary" onClick={() => setValue("123456")}>
Fill 123456
</Button>
<Button size="xs" variant="secondary" onClick={() => setValue("")}>
Clear
</Button>
</Stack>
<PinField.Root size="md">
<PinField.Label>Verification code</PinField.Label>
<PinField.Input name="controlled" length={6} value={value} onChange={({ value }) => setValue(value)} />
</PinField.Root>
<Text size="body-sm-desktop">Value: "{value}"</Text>
</Stack>
);
};Initial Value and Form Reset
Set defaultValue for an uncontrolled field. A native form reset restores that value.
import { Button, PinField, Stack } from "@vortexlabs/vortex";
<form>
<Stack gap={3}>
<PinField.Root size="md">
<PinField.Label>Resettable code</PinField.Label>
<PinField.Input name="resettable-code" length={6} defaultValue="12" />
<PinField.HelperText>Reset restores the initial value 12.</PinField.HelperText>
</PinField.Root>
<Button type="reset" size="sm" variant="tertiary">Reset</Button>
</Stack>
</form>Accessibility
Key
Description
TabShiftTab
Move into or out of the field; the cells share one native input.
Left arrowRight arrow
Move between cells (directions swap in right-to-left layouts).
HomeUp arrow
Move to the first cell.
EndDown arrow
Move to the first empty cell, or the last cell when the code is full.
Include
PinField.Label or provide attributes["aria-label"] on the input.Helper and error messages are connected to the input with
aria-describedby.Validate the full code in your application;
required checks for a non-empty value, not the configured length.