Refined UI

An opinionated, customizable superset of shadcn/ui

AgentsPrimitivesSkillsSkins
Guides
  • Overview
  • Get started
  • Shadcn compatibility
  • Architecture
  • Agent surface
Primitives
  • Accordion
  • Alert
  • Alert dialog
  • Aspect ratio
  • Autocomplete
  • Avatar
  • Badge
  • Button
  • Button group
  • Calendar
  • Card
  • Checkbox
  • Checkbox Group
  • Code
  • Code Diff
  • Collapsible
  • Color Picker
  • Combobox
  • Command
  • Date Picker
  • Dialog
  • Drawer
  • Empty
  • Field
  • Form
  • Gradient Editor
  • Hover card
  • Input
  • Input group
  • Input OTP
  • Item
  • Kbd
  • Markdown
  • Menu
  • Menubar
  • Meter
  • Native select
  • Navigation menu
  • Number Field
  • Pagination
  • Popover
  • Progress
  • Radio group
  • Resizable
  • Scroll area
  • Select
  • Sidebar
  • Skeleton
  • Slider
  • Spinner
  • Switch
  • Table
  • Table of contents
  • Tabs
  • Textarea
  • Toast
  • Toggle
  • Toolbar
  • Tooltip
  • Tree
  • Trigger Menu
  • Typography
Hooks
  • Use Chat Message
  • Use Chat Input
  • Use User Ask
  • Use Audio Recorder
  • Use Environment Variables
  • Use Copy To Clipboard
  • Use Tool Call
  • Use Sidebar Resize
Utils
  • cn
  • Skin
  • Contracts
  • Serialize
Extensions
  • Control Effects
  • View Transition
  • Send Aurora
  1. Primitives
  2. Input OTP
Primitives

Input OTP

One-time-code field with grouped, focus-aware slots.

Composition

The preferred shape for composing the installed primitive from its exported parts.

Parts

Exported compound parts from the installed source.

InputOTPSlot
├── InputOTPSeparator
└── InputOTP

The refined source installs this primitive from src/registry/sources/refined/ui/input-otp.tsx. Install it on its own with the command above, or inspect the source below.

Registry command
npx shadcn@latest add http://127.0.0.1:3000/r/refined/input-otp.json
See registry manifest

Raw code

Primary installed primitive source

Base UI OtpField slot
src/registry/sources/refined/ui/input-otp.tsx
"use client";
​
import { OTPField as OTPFieldPrimitive } from "@base-ui/react/otp-field";
import { Fragment } from "react";
import type { InputOTPProps, InputOTPSeparatorProps, InputOTPSlotProps } from "@/components/refined-ui/contracts";
import { cn } from "@/components/refined-ui/lib/cn";
import { skinSlot } from "@/components/refined-ui/skin";
​
// Refined skin slot, 100% Base UI OtpField: each slot a control-shaped box sharing --radius-control/card+ring surface w/ Input & Select trigger.
// Code reads as a row of the same control family; focused slot lifts ring in pure CSS.
const slotClasses =
"relative flex size-[var(--control-h-md)] items-center justify-center rounded-[var(--radius-control)] bg-card/72 text-center text-body font-medium tabular-nums text-foreground shadow-sm ring-1 ring-inset ring-border outline-none transition placeholder:text-muted-foreground focus:z-[1] focus:ring-2 focus:ring-foreground/20 data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50";
​
export function InputOTPSlot({ index, length, className, ...props }: InputOTPSlotProps) {
return (
<OTPFieldPrimitive.Input
data-ui="agent"
data-slot="input-otp-slot"
data-control="true"
aria-label={length ? `Character ${index + 1} of ${length}` : `Character ${index + 1}`}
className={cn(slotClasses, skinSlot("input-otp-slot", {}), className)}
{...props}
/>
);
}
​
export function InputOTPSeparator({ className, ...props }: InputOTPSeparatorProps) {
return (
<OTPFieldPrimitive.Separator
data-ui="agent"
data-slot="input-otp-separator"
className={cn("h-px w-2.5 shrink-0 rounded-full bg-border", skinSlot("input-otp-separator", {}), className)}
{...props}
/>
);
}
​
export function InputOTP({ length = 6, separator = false, className, children, ...props }: InputOTPProps) {
return (
<OTPFieldPrimitive.Root
data-ui="agent"
data-slot="input-otp"
length={length}
className={cn("flex items-center gap-2", skinSlot("input-otp", {}), className)}
{...props}
>
{children ??
Array.from({ length }, (_, index) => `input-otp-slot-${index}`).map((slotKey, index) => (
<Fragment key={slotKey}>
{separator && index === Math.ceil(length / 2) ? <InputOTPSeparator /> : null}
<InputOTPSlot index={index} length={length} />
</Fragment>
))}
</OTPFieldPrimitive.Root>
);
}
​

On this page

  • Preview
  • Composition
  • Installation
  • Source
Enter the 6-digit code (0/6)