@rozie-ui/otp-solid
v0.1.5
Published
Idiomatic Solid headless WAI-ARIA one-time-code / PIN input (segmented cells, paste-to-distribute, keyboard nav, SMS autofill, masking) — one accessible Rozie source compiled to Solid.
Maintainers
Readme
@rozie-ui/otp-solid
Idiomatic solid Otp — a headless, fully-accessible (WAI-ARIA) one-time-code / PIN input (segmented native cells, paste-to-distribute, full keyboard navigation, autocomplete="one-time-code" SMS autofill, and optional masking) compiled from one Rozie source. The interaction engine IS the browser's native <input> cells; every visual value is a CSS custom property, so it re-skins to any design system. This package is generated; do not edit src/ by hand.
Install
npm i @rozie-ui/otp-solidPeer dependencies: solid-js. Install them alongside this package.
Also installed: @rozie/runtime-solid — Rozie's small, tree-shaken runtime helper package (controllable state, keyboard navigation, event modifiers, and safe interpolation). It arrives as a regular dependency, so npm pulls it for you. Your bundler keeps only the helpers this component actually uses — typically a few hundred bytes to a few KB, minified and gzipped. What's in it and what it costs.
Usage
import { createSignal } from 'solid-js';
import { Otp } from '@rozie-ui/otp-solid';
export function Demo() {
const [code, setCode] = createSignal<string>('');
return (
<Otp
value={code()}
onValueChange={setCode}
length={6}
type="numeric"
ariaLabel="Verification code"
onComplete={(e) => console.log('code complete:', e.value)}
/>
);
}Theming
Every visual value is a --rozie-otp-* CSS custom property — override any of them at any ancestor scope. Ready-made design-system bridges ship in the package:
import '@rozie-ui/otp-solid/themes/shadcn.css'; // or material.css, bootstrap.css, base.cssProps
| Name | Type | Default | Two-way (model) | Required |
| --- | --- | --- | :---: | :---: |
| value | String | '' | ✓ | |
| length | Number | 6 | | |
| type | String | "numeric" | | |
| mask | Boolean | false | | |
| autoFocus | Boolean | false | | |
| disabled | Boolean | false | | |
| placeholder | String | '' | | |
| ariaLabel | String | null | | |
Events
| Event | Description |
| --- | --- |
| change | Fired on every edit (type, paste, backspace, or a programmatic clear) that actually changes the code — a write that produces the same value does not re-emit. Payload { value } — the new contiguous code string (0..length chars). Funneled through one commitValue wrapper so the React prop-destructure hoists exactly once. |
| complete | Fired on the not-full → full transition, i.e. the code reaches length characters. Editing a cell of an already-complete code does not re-fire it, and clear() never fires it. Payload { value } — the complete code string. Use it to auto-submit a verification flow. |
Imperative handle
Beyond props, the component exposes imperative methods (declared once in the Rozie source via $expose). Grab a handle with the native ref mechanism and call them directly. Note: focus() deliberately overrides the inherited HTMLElement.focus (it focuses the first empty cell) — on the Lit custom element this is an accepted ROZ137 warn-only override, the public focus() handle is intended:
| Method | Description |
| --- | --- |
| focus | Move DOM focus to the first empty cell (clamped to the last cell when the code is full). NOTE: this deliberately overrides the inherited HTMLElement.focus on the Lit custom element (ROZ137 warns, warn-only) — the public focus() handle is intended. |
| clear | Reset the code to the empty string (emits change with { value: "" }) and move focus to the first cell. |
import { Otp, type OtpHandle } from '@rozie-ui/otp-solid';
let handle: OtpHandle | undefined;
// The ref callback receives the HANDLE object (not the DOM node).
<Otp ref={(h) => (handle = h)} value={code()} />;
handle?.clear();Slots
This component declares no slots.
