- Accordion
- Alert
- Alert Dialog
- Aspect Ratio
- Attachment
- Avatar
- Badge
- Breadcrumb
- Bubble
- Button
- Button Group
- Card
- Checkbox
- Collapsible
- Combobox
- Context Menu
- Date Picker (Lite)
- Dialog
- Direction
- Drawer
- Dropdown Menu
- Empty
- Field
- Hover Card
- Input
- Input Group
- Input OTP (Lite)
- Item
- Kbd
- Label
- Marker
- Menubar
- Message
- Native Select
- Navigation Menu
- Pagination
- Popover
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toast
- Toggle
- Toggle Group
- Tooltip
import { InputOTPLite } from "@/components/ui/input-otp-lite"
export default function InputOTPLiteDemo() {
return <InputOTPLite maxLength={6} name="code" aria-label="One-time code" />
}About
Input OTP (Lite) is a hand-written alternative to shadcn/ui's Input OTP, which is built on the React library input-otp. It keeps upstream's look in every style: one native text input lies over the slot boxes, its characters spaced to one per box, so typing, pasting, one-time-code autofill and form validation come from the browser.
Installation
pnpm dlx shadcnui-hono-jsx@latest add input-otp-litenpx shadcnui-hono-jsx@latest add input-otp-liteyarn dlx shadcnui-hono-jsx@latest add input-otp-litebunx shadcnui-hono-jsx@latest add input-otp-liteUsage
import { InputOTPLite } from "@/components/ui/input-otp-lite"<InputOTPLite maxLength={6} name="code" />Unlike upstream, it is one component: maxLength sets the number of slots, and the input takes every attribute of a text input (name, pattern, required, value, disabled, aria-*).
Pattern
Use pattern and inputmode for what the code accepts. Characters line up with tabular digits; set a monospace font for letters.
import { InputOTPLite } from "@/components/ui/input-otp-lite"
export default function InputOTPLitePattern() {
return (
<InputOTPLite
maxLength={6}
pattern="[A-Za-z0-9]{6}"
inputmode="text"
class="font-mono uppercase"
aria-label="Invite code"
/>
)
}Four Digits
import { InputOTPLite } from "@/components/ui/input-otp-lite"
export default function InputOTPLiteFourDigits() {
return <InputOTPLite maxLength={4} pattern="[0-9]{4}" aria-label="PIN" />
}Disabled
import { InputOTPLite } from "@/components/ui/input-otp-lite"
export default function InputOTPLiteDisabled() {
return (
<InputOTPLite maxLength={6} value="123456" disabled aria-label="Code" />
)
}Invalid
Set aria-invalid to show the invalid state.
import { InputOTPLite } from "@/components/ui/input-otp-lite"
export default function InputOTPLiteInvalid() {
return (
<InputOTPLite maxLength={6} value="000000" aria-invalid aria-label="Code" />
)
}Form
It submits with the form, and the browser validates required, minlength (set to maxLength) and pattern.
import { Button } from "@/components/ui/button"
import {
Field,
FieldDescription,
FieldGroup,
FieldLabel,
} from "@/components/ui/field"
import { InputOTPLite } from "@/components/ui/input-otp-lite"
export default function InputOTPLiteForm() {
return (
<form class="w-full max-w-xs" method="post">
<FieldGroup>
<Field>
<FieldLabel for="otp">One-Time Password</FieldLabel>
<InputOTPLite
id="otp"
name="otp"
maxLength={6}
pattern="[0-9]{6}"
required
/>
<FieldDescription>
Enter the 6-digit code sent to your phone.
</FieldDescription>
</Field>
<Button type="submit" class="w-fit">
Verify
</Button>
</FieldGroup>
</form>
)
}Notes
- A lite alternative to
input-otp(not a port), with no JavaScript: one native text input over the slots, as in daisyUI, so typing, pasting, one-time-code autofill (autocomplete="one-time-code") and form validation (minlength,pattern,required) come from the browser. - One component with
maxLengthslots instead ofInputOTPGroup,InputOTPSlotandInputOTPSeparator; the whole group is highlighted while focused (upstream highlights the active slot, with a blinking caret). Characters are aligned with tabular digits: set a monospace font (class="font-mono") for letters. - Accepts
classinstead ofclassName. - Upstream documentation: shadcn/ui Input OTP. See also Differences from shadcn/ui.