PIN Input
Allows users to input a sequence of one-character alphanumeric inputs.
<script lang="ts">
import { PinInput, Toggle, type PinInputRootSnippetProps } from "bits-ui";
import { cn } from "$lib/utils/styles.js";
import { toast } from "svelte-sonner";
let value = $state("");
type CellProps = PinInputRootSnippetProps["cells"][0];
function onComplete() {
toast.success("Completed with value " + value);
value = "";
}
</script>
<PinInput.Root
bind:value
class="group/pininput flex items-center text-foreground has-[:disabled]:opacity-30"
maxlength={6}
{onComplete}
>
{#snippet children({ cells })}
<div class="flex">
{#each cells.slice(0, 3) as cell}
{@render Cell(cell)}
{/each}
</div>
<div class="flex w-10 items-center justify-center">
<div class="h-1 w-3 rounded-full bg-border"></div>
</div>
<div class="flex">
{#each cells.slice(3, 6) as cell}
{@render Cell(cell)}
{/each}
</div>
{/snippet}
</PinInput.Root>
{#snippet Cell(props: CellProps)}
<div
class={cn(
// Custom class to override global focus styles
"focus-override",
"relative h-14 w-10 text-[2rem]",
"flex items-center justify-center",
"transition-all duration-200",
"border-y border-r border-foreground/20 first:rounded-l-md first:border-l last:rounded-r-md",
"text-foreground group-focus-within/pininput:border-foreground/40 group-hover/pininput:border-foreground/40",
"outline outline-0",
props.isActive && "outline-1 outline-white"
)}
>
{#if props.char !== null}
<div>
{props.char}
</div>
{/if}
{#if props.hasFakeCaret}
<div
class="pointer-events-none absolute inset-0 flex animate-caret-blink items-center justify-center"
>
<div class="h-8 w-px bg-white"></div>
</div>
{/if}
</div>
{/snippet}
This component is derived from and would not have been possible without the work done by Input OTP by Guilherme Rodz.
Structure
<script lang="ts">
import { PinInput } from "bits-ui";
</script>
<PinInput.Root maxlength={6}>
{#snippet children({ cells })}
{#each cells as cell}
{cell.char !== null ? cell.char : ""}
{/each}
{/snippet}
</PinInput.Root>
API Reference
The root component which contains the pin-input.
Property | Type | Description |
---|---|---|
placeholder | string | The placeholder character to use for empty pin-inputs. Default: ○ |
value | string[] | The value of the pin-input. Default: undefined |
name | string | The name of the pin-input. This is used for form submission. Default: undefined |
disabled | boolean | Whether or not the pin-input is disabled. Default: false |
type | 'text' | 'password' | The type of the input. Use Default: text |
onValueChange | function | A callback function called when the pin-input value changes. Default: undefined |
asChild | boolean | Whether to use render delegation with this component or not. Default: false |
el | HTMLDivElement | The underlying DOM element being rendered. You can bind to this to programatically interact with the element. Default: undefined |
Slot Property | Type | Description |
---|---|---|
builder | object | The builder attributes and actions to apply to the element if using the |
ids | object | The ids of the elements within the component, useful when you don't necessarily want to provide a custom ID, but still want access to the ID being assigned (if any). |
Data Attribute | Value | Description |
---|---|---|
data-pin-input-root | —— | Present on the root element. |
data-complete | —— | Present if the pin-input is complete. |
The input component which contains the pin-input.
Property | Type | Description |
---|---|---|
asChild | boolean | Whether to use render delegation with this component or not. Default: false |
el | HTMLInputElement | The underlying DOM element being rendered. You can bind to this to programatically interact with the element. Default: undefined |
Data Attribute | Value | Description |
---|---|---|
data-pin-input-input | —— | Present on the input element. |
data-complete | —— | Present if the pin-input is complete. |
The hidden input component which contains the pin-input.
Property | Type | Description |
---|---|---|
asChild | boolean | Whether to use render delegation with this component or not. Default: false |
el | HTMLInputElement | The underlying DOM element being rendered. You can bind to this to programatically interact with the element. Default: undefined |
Data Attribute | Value | Description |
---|---|---|
data-pin-input-hidden-input | —— | Present on the hidden input element. |