Input OTP
[tngInputOtp] is the headless state primitive for OTP roots. You own the actual inputs, keyboard handling, and slot layout while the primitive reflects mirrored state onto the host.
Imports
Primitive import
ts
import {
TngInputOtp as TngInputOtpPrimitive,
TngInputOtpSlot,
} from '@tailng-ui/primitives';Usage baseline
The primitive does not render slots for you, but the root and slot directives coordinate the baseline OTP behavior so your page only owns markup and styling.
Minimal headless composition
html
<div
tngInputOtp
[length]="6"
[value]="verificationCode()"
(valueChange)="verificationCode.set($event)"
[activeIndex]="activeIndex()"
(activeIndexChange)="activeIndex.set($event)"
>
@for (slotIndex of verificationSlotIndexes; track slotIndex) {
<input [tngInputOtpSlot]="slotIndex" maxlength="1" inputmode="numeric" />
}
</div>OTP variants
Compare the same primitive composition across plain CSS and Tailwind CSS while keeping the slot markup fully owned.
Input OTP (Plain-CSS)
Verification code
Own the slot markup directly while the primitive reflects root state for styling.
Value: 18
State: partial
Input OTP (Tailwind CSS)
Approval code
Same primitive contract, utility-first shell, and fully owned slot markup.
Value: 40
State: partial
Behavior baseline
- You own the slot markup and styling, while the primitive handles baseline OTP keyboard flow.
- The primitive mirrors combined value state through
data-empty,data-partial, anddata-complete. valueChangeandactiveIndexChangelet headless pages stay controlled without reimplementing focus movement.