Text Field
Single-line text input control with control radius (--radius-lg), leading/trailing icon slots, and optional label/hint wrapper.
// Plain markup
import { TextField } from "@shavin/ui";Default usage
Component Source
const [value, setValue] = useState("");
<TextField
className="w-64"
placeholder="Enter a value…"
value={value}
onChange={(e) => setValue(e.target.value)}
/>With Icons
Component Source
{/* Leading Icon */}
<TextField placeholder="Search…" leadingIcon={<SearchIcon />} />
{/* Trailing Icon */}
<TextField placeholder="you@example.com" trailingIcon={<MailIcon />} />
{/* Both Icons */}
<TextField placeholder="Search email…" leadingIcon={<SearchIcon />} trailingIcon={<MailIcon />} />Variants (Invalid & Disabled)
Component Source
{/* Invalid state */}
<TextField placeholder="Required field" invalid defaultValue="bad value" />
{/* Disabled state */}
<TextField placeholder="Can't touch this" disabled />Sizes
Component Source
<TextField size="sm" placeholder="Small" />
<TextField size="md" placeholder="Medium" />
<TextField size="sm" placeholder="Small + icon" leadingIcon={<SearchIcon />} />OTP Verification Code
Type='otp' renders single-input accessible verification slots with live focus caret, 1-tap SMS autofill, and paste support.
Type='otp' renders single-input accessible verification slots with live focus caret, 1-tap SMS autofill, and paste support.
const [otp, setOtp] = useState("");
<TextField
type="otp"
length={6}
label="Verification Code"
hint="Enter the 6-digit code sent to your email."
value={otp}
onChange={(e) => setOtp(e.target.value)}
onComplete={(code) => alert(`Verified: ${code}`)}
/>OTP Split & Masked PIN
Split 3-3 digits with separator or mask sensitive PIN codes.
-
Split 3-3 digits with separator or mask sensitive PIN codes.
{/* 3-3 Split with separator */}
<TextField
type="otp"
length={6}
separator="-"
separatorIndex={3}
label="Two-factor Authentication"
/>
{/* Masked 4-digit PIN */}
<TextField
type="otp"
length={4}
mask
label="Security PIN"
hint="4-digit numerical secret PIN"
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
| leadingIcon | ReactNode | — | Icon rendered inside the field, pinned to the left edge. |
| trailingIcon | ReactNode | — | Icon rendered inside the field, pinned to the right edge. |
| label | string | — | Optional label text rendered above the field. |
| hint | string | — | Optional hint/helper text rendered below the field. |
| length | number | string | 6 | Number of digits/slots when type="otp". Default 6. |
| mask | boolean | false | Whether to mask digits with bullet dots (for PIN / password OTP codes) or mask password text. Default false. |
| separator | ReactNode | — | Optional separator element or character rendered midway (e.g. '-' or index=3 for 3-3 split). |
| separatorIndex | number | — | Index position to render the separator (defaults to Math.floor(length / 2)). |
| onComplete | (code: string) => void | — | Callback fired when all OTP digits have been entered. |
| slotClassName | string | — | Optional custom CSS class name applied directly to individual OTP slot boxes. |
| showHidePassword | boolean | — | Password-only: render the built-in show/hide (Eye/EyeOff) trailing button. Ignored for other types. |
| errorMessage | string | — | Error message text — when set, the field renders in invalid/error state and shows this message below the input. |
| size | "sm" | "md" | "lg" | "md" | — |
| invalid | "true" | "false" | "false" | — |