Input OTP
---import { InputOtp, InputOtpGroup, InputOtpSlot,} from "@/components/starwind/input-otp";---
<InputOtp aria-label="Verification code" maxLength={6}> <InputOtpGroup> <InputOtpSlot index={0} /> <InputOtpSlot index={1} /> <InputOtpSlot index={2} /> <InputOtpSlot index={3} /> <InputOtpSlot index={4} /> <InputOtpSlot index={5} /> </InputOtpGroup></InputOtp>import { InputOtp, InputOtpGroup, InputOtpSlot,} from "@/components/starwind/input-otp";
export function Example() { return ( <InputOtp aria-label="Verification code" maxLength={6}> <InputOtpGroup> <InputOtpSlot index={0} /> <InputOtpSlot index={1} /> <InputOtpSlot index={2} /> <InputOtpSlot index={3} /> <InputOtpSlot index={4} /> <InputOtpSlot index={5} /> </InputOtpGroup> </InputOtp> );}Runtime example adjustment
Input OTP now delegates keyboard navigation, paste distribution, pattern filtering, hidden form input synchronization, and reset behavior to the Runtime. Give the root an accessible name because its visible slots share one hidden input.
Installation
pnpx starwind@latest add input-otpnpx starwind@latest add input-otpyarn dlx starwind@latest add input-otpFramework Availability
Astro Available React AvailableInput Otp is available for Astro and React.
Usage
General Notes
The Input OTP component provides a user-friendly way to input one-time passwords and verification codes. It supports keyboard navigation, paste handling, and pattern validation.
The essential components are InputOtp, InputOtpGroup, and InputOtpSlot. The InputOtpSeparator provides visual separation between groups of slots.
With Separator
Use InputOtpSeparator to visually group slots, commonly used for phone verification codes or formatted inputs.
---import { InputOtp, InputOtpGroup, InputOtpSeparator, InputOtpSlot,} from "@/components/starwind/input-otp";---
<InputOtp aria-label="Verification code with separator" maxLength={6}> <InputOtpGroup> <InputOtpSlot index={0} /> <InputOtpSlot index={1} /> <InputOtpSlot index={2} /> </InputOtpGroup> <InputOtpSeparator /> <InputOtpGroup> <InputOtpSlot index={3} /> <InputOtpSlot index={4} /> <InputOtpSlot index={5} /> </InputOtpGroup></InputOtp>Accessibility adjustment
Name the InputOtp root rather than its individual slots; Runtime exposes the shared name on the hidden input.
Alphanumeric Pattern
Use the pattern prop with REGEXP_ONLY_DIGITS_AND_CHARS to allow both letters and numbers.
---import { InputOtp, InputOtpGroup, InputOtpSlot, REGEXP_ONLY_DIGITS_AND_CHARS,} from "@/components/starwind/input-otp";---
<InputOtp aria-label="Alphanumeric verification code" maxLength={6} pattern={REGEXP_ONLY_DIGITS_AND_CHARS}> <InputOtpGroup> <InputOtpSlot index={0} /> <InputOtpSlot index={1} /> <InputOtpSlot index={2} /> <InputOtpSlot index={3} /> <InputOtpSlot index={4} /> <InputOtpSlot index={5} /> </InputOtpGroup></InputOtp>Accessibility adjustment
Keep an explicit accessible name when the pattern changes what characters the shared input accepts.
Sizes
The InputOtpSlot component supports three sizes: sm, md (default), and lg.
Small
Medium (default)
Large
---import { InputOtp, InputOtpGroup, InputOtpSlot,} from "@/components/starwind/input-otp";---
<div class="flex flex-col gap-6"> <div class="space-y-2"> <p class="text-muted-foreground text-sm">Small</p> <InputOtp aria-label="Small verification code" maxLength={4}> <InputOtpGroup> <InputOtpSlot index={0} size="sm" /> <InputOtpSlot index={1} size="sm" /> <InputOtpSlot index={2} size="sm" /> <InputOtpSlot index={3} size="sm" /> </InputOtpGroup> </InputOtp> </div> <div class="space-y-2"> <p class="text-muted-foreground text-sm">Medium (default)</p> <InputOtp aria-label="Medium verification code" maxLength={4}> <InputOtpGroup> <InputOtpSlot index={0} size="md" /> <InputOtpSlot index={1} size="md" /> <InputOtpSlot index={2} size="md" /> <InputOtpSlot index={3} size="md" /> </InputOtpGroup> </InputOtp> </div> <div class="space-y-2"> <p class="text-muted-foreground text-sm">Large</p> <InputOtp aria-label="Large verification code" maxLength={4}> <InputOtpGroup> <InputOtpSlot index={0} size="lg" /> <InputOtpSlot index={1} size="lg" /> <InputOtpSlot index={2} size="lg" /> <InputOtpSlot index={3} size="lg" /> </InputOtpGroup> </InputOtp> </div></div>Accessibility adjustment
Size is visual, so each preview uses a distinct accessible name instead of relying on the nearby size caption.
Disabled
Use the disabled prop to prevent user interaction.
---import { InputOtp, InputOtpGroup, InputOtpSlot,} from "@/components/starwind/input-otp";---
<InputOtp aria-label="Verification code" maxLength={6} disabled> <InputOtpGroup> <InputOtpSlot index={0} /> <InputOtpSlot index={1} /> <InputOtpSlot index={2} /> <InputOtpSlot index={3} /> <InputOtpSlot index={4} /> <InputOtpSlot index={5} /> </InputOtpGroup></InputOtp>Accessibility adjustment
Disabled controls still need an accessible name so assistive technology can identify them.
Form Submission
The component integrates with native HTML forms using the name prop. The hidden input stores the complete OTP value.
---import { Button } from "@/components/starwind/button";import { InputOtp, InputOtpGroup, InputOtpSlot,} from "@/components/starwind/input-otp";import { Label } from "@/components/starwind/label";---
<form id="otp-demo-form" class="space-y-4"> <div class="space-y-2"> <Label for="otp-form">Verification Code</Label> <InputOtp id="otp-form" name="otp" maxLength={6} required> <InputOtpGroup> <InputOtpSlot index={0} /> <InputOtpSlot index={1} /> <InputOtpSlot index={2} /> <InputOtpSlot index={3} /> <InputOtpSlot index={4} /> <InputOtpSlot index={5} /> </InputOtpGroup> </InputOtp> </div> <Button type="submit">Submit Code</Button></form><div id="form-result" class="bg-muted mt-4 hidden rounded-md p-4 font-mono text-sm"></div>
<script> const form = document.getElementById("otp-demo-form") as HTMLFormElement; const resultDiv = document.getElementById("form-result");
if (form && resultDiv) { form.addEventListener("submit", (e) => { e.preventDefault(); const formData = new FormData(form); const otp = formData.get("otp");
resultDiv.textContent = `Submitted OTP: ${otp}`; resultDiv.classList.remove("hidden"); }); }</script>Value changes
Listen on the Input OTP root for starwind:value-change. Its detail includes value, previousValue, reason, and inputOtpId; the event is cancelable before Runtime commits the change.
<InputOtp id="verification-code" aria-label="Verification code" maxLength={6}> <InputOtpGroup> <InputOtpSlot index={0} /> <InputOtpSlot index={1} /> <InputOtpSlot index={2} /> <InputOtpSlot index={3} /> <InputOtpSlot index={4} /> <InputOtpSlot index={5} /> </InputOtpGroup></InputOtp>
<script> const root = document.querySelector<HTMLElement>("#verification-code"); root?.addEventListener("starwind:value-change", (event) => { const { value, reason } = ( event as CustomEvent<{ value: string; reason: string }> ).detail; console.log(value, reason); });</script>Runtime example adjustment
Use the shared Runtime value-change contract for new integrations. The older starwind-input-otp:change event remains a compatibility event with less detail.
API Reference
Styled Component API
These props are added or materially changed by the installed Astro styled component. Standard HTML attributes remain available through the inherited interfaces noted below. Follow the Primitive and Runtime links for lower-level behavior props.
Input Otp Slot
Inherits div attributes.
Contains the following additional props:
size "sm" | "md" | "lg" "md"
- Description
- Selects the component's visual size.
- Classification
- Styled variant
Primitive And Runtime API
Use these references when you need the lower-level behavior APIs behind Input Otp.
Primitive API
Runtime API
- Input Otp primitive
createInputOtpfrom@starwind-ui/runtime/input-otp
Changelog
v2.0.0
- Rebuilt Input OTP on Starwind Runtime for value state, form participation, paste handling, and value-change events.
- See the Input OTP Primitive for the underlying unstyled anatomy and behavior API.
v1.0.3
- Refactor tailwind variants functions into separate
variants.tsfile
v1.0.1
- Auto focus hidden input on click to automatically open keyboards on mobile devices
- Update component to always focus the next empty index on click
v1.0.0
- Initial release with starwind v1.15.0