Biji UI

PIN Input

A sequence of single-character input cells for entering PINs, OTPs, and verification codes.

Enter verification code

We sent a 6-digit code to your email.

Installation

biji-ui = { version = "0.5.0", features = ["pin_input"] }

Usage

use leptos::prelude::*;
use biji_ui::components::pin_input;

#[component]
pub fn MyPinInput() -> impl IntoView {
    view! {
        <pin_input::Root
            length=6
            class="flex gap-2"
            on_complete={Callback::new(|code: String| {
                leptos::logging::log!("PIN complete: {code}");
            })}
        >
            <pin_input::Cell index=0 class="w-10 h-12 text-center text-lg rounded-md border border-input bg-background focus:outline-none focus:ring-2 focus:ring-ring data-[filled]:border-primary" />
            <pin_input::Cell index=1 class="w-10 h-12 text-center text-lg rounded-md border border-input bg-background focus:outline-none focus:ring-2 focus:ring-ring data-[filled]:border-primary" />
            <pin_input::Cell index=2 class="w-10 h-12 text-center text-lg rounded-md border border-input bg-background focus:outline-none focus:ring-2 focus:ring-ring data-[filled]:border-primary" />
            <pin_input::Cell index=3 class="w-10 h-12 text-center text-lg rounded-md border border-input bg-background focus:outline-none focus:ring-2 focus:ring-ring data-[filled]:border-primary" />
            <pin_input::Cell index=4 class="w-10 h-12 text-center text-lg rounded-md border border-input bg-background focus:outline-none focus:ring-2 focus:ring-ring data-[filled]:border-primary" />
            <pin_input::Cell index=5 class="w-10 h-12 text-center text-lg rounded-md border border-input bg-background focus:outline-none focus:ring-2 focus:ring-ring data-[filled]:border-primary" />
        </pin_input::Root>
    }
}

RootWith

Use <RootWith> when you need direct access to PinInputState inside the children. The let:s binding exposes s.value and s.is_complete as reactive signals — no callbacks needed for reading state.

Enter 4-digit code

use leptos::prelude::*;
use biji_ui::components::pin_input;

#[component]
pub fn MyPinInput() -> impl IntoView {
    const CELL_CLS: &str = "w-11 h-13 text-center text-xl font-mono rounded-md border \
        border-input bg-background focus:outline-none focus:ring-2 focus:ring-ring \
        data-[filled]:border-primary placeholder:text-muted-foreground/40";

    view! {
        <pin_input::RootWith length=4 class="flex flex-col items-center gap-4" let:s>
            <div class="flex gap-2">
                <pin_input::Cell index=0 class={CELL_CLS} />
                <pin_input::Cell index=1 class={CELL_CLS} />
                <pin_input::Cell index=2 class={CELL_CLS} />
                <pin_input::Cell index=3 class={CELL_CLS} />
            </div>
            <p class="text-xs text-muted-foreground">
                {move || if s.is_complete.get() {
                    format!("Code: {}", s.value.get())
                } else {
                    format!("{}/4 digits entered", s.value.get().len())
                }}
            </p>
        </pin_input::RootWith>
    }
}

API Reference

Root / RootWith

NameTypeDefaultDescription
classString""CSS class applied to the root wrapper element.
lengthusize4The total number of PIN cells.
disabledboolfalseWhen true, all cells are disabled.
placeholderString"○"Placeholder character shown in each empty cell.
on_completeOption<Callback<String>>NoneCallback fired with the full PIN string when every cell is filled.

Cell

NameTypeDefaultDescription
indexusize Zero-based position of this cell within the PIN input.
classString""CSS class applied to the input element.

Data Attributes

AttributeDescription
data-filledPresent on Cell when the cell has a value entered.
data-disabledPresent on Root and Cell when the input is disabled.
data-indexThe zero-based index of the cell. Present on Cell.

Keyboard Navigation

KeyDescription
0–9 / Any characterTypes a character into the current cell and advances focus to the next cell.
BackspaceClears the current cell. If already empty, clears the previous cell and moves focus back.
ArrowLeftMoves focus to the previous cell.
ArrowRightMoves focus to the next cell.
Paste (Ctrl+V / Cmd+V)Pastes a string of characters distributed across cells starting at the focused cell.