# PIN Input Documentation Allows users to input a sequence of one-character alphanumeric inputs. This is a documentation section that potentially contains examples, demos, and other useful information related to a specific part of Bits UI. When helping users with this documentation, you can ignore the classnames applied to the demos unless they are relevant to the user's issue. ```svelte {#snippet children({ cells })}
{#each cells.slice(0, 3) as cell} {@render Cell(cell)} {/each}
{#each cells.slice(3, 6) as cell} {@render Cell(cell)} {/each}
{/snippet}
{#snippet Cell(cell: CellProps)} {#if cell.char !== null}
{cell.char}
{/if} {#if cell.hasFakeCaret} {/if}
{/snippet} ``` ## Overview The PIN Input component provides a customizable solution for One-Time Password (OTP), Two-Factor Authentication (2FA), or Multi-Factor Authentication (MFA) input fields. Due to the lack of a native HTML element for these purposes, developers often resort to either basic input fields or custom implementations. This component offers a robust, accessible, and flexible alternative. ##### Credits This component is derived from and would not have been possible without the work done by [Guilherme Rodz](https://x.com/guilhermerodz) with [Input OTP](https://github.com/guilhermerodz/input-otp). ## Key Features - **Invisible Input Technique**: Utilizes an invisible input element for seamless integration with form submissions and browser autofill functionality. - **Customizable Appearance**: Allows for custom designs while maintaining core functionality. - **Accessibility**: Ensures keyboard navigation and screen reader compatibility. - **Flexible Configuration**: Supports various PIN lengths and input types (numeric, alphanumeric). ## Architecture 1. **Root Container**: A relatively positioned root element that encapsulates the entire component. 2. **Invisible Input**: A hidden input field that manages the actual value and interacts with the browser's built-in features. 3. **Visual Cells**: Customizable elements representing each character of the PIN, rendered as siblings to the invisible input. This structure allows for a seamless user experience while providing developers with full control over the visual representation. ## Structure ```svelte {#snippet children({ cells })} {#each cells as cell} {/each} {/snippet} ``` ## Managing Value State This section covers how to manage the `value` state of the component. ### Two-Way Binding Use `bind:value` for simple, automatic state synchronization: ```svelte ``` ### Fully Controlled Use a [Function Binding](https://svelte.dev/docs/svelte/bind#Function-bindings) for complete control over the state's reads and writes. ```svelte ``` ## Paste Transformation The `pasteTransformer` prop allows you to sanitize/transform pasted text. This can be useful for cleaning up pasted text, like removing hyphens or other characters that should not make it into the input. This function should return the sanitized text, which will be used as the new value of the input. ```svelte text.replace(/-/g, "")}> ``` ## HTML Forms The `PinInput.Root` component is designed to work seamlessly with HTML forms. Simply pass the `name` prop to the `PinInput.Root` component and the input will be submitted with the form. ### Submit On Complete To submit the form when the input is complete, you can use the `onComplete` prop. ```svelte
form.submit()}>
``` ## Patterns You can use the `pattern` prop to restrict the characters that can be entered or pasted into the input. ##### Note! Client-side validation cannot replace server-side validation. Use this in addition to server-side validation for an improved user experience. Bits UI exports a few common patterns that you can import and use in your application. - `REGEXP_ONLY_DIGITS` \- Only allow digits to be entered. - `REGEXP_ONLY_CHARS` \- Only allow characters to be entered. - `REGEXP_ONLY_DIGITS_AND_CHARS` \- Only allow digits and characters to be entered. ```svelte ``` ## API Reference ### PINInput.Root The pin input container component. | Property | Type | Description | | -------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `value` $bindable | `string` | The value of the input.`Default: undefined` | | `onValueChange` | `function`- (value: string) => void | A callback function that is called when the value of the input changes.`Default: undefined` | | `disabled` | `boolean` | Whether or not the pin input is disabled.`Default: false` | | `textalign` | `enum`- 'left' \| 'center' \| 'right' | Where is the text located within the input. Affects click-holding or long-press behavior`Default: 'left'` | | `maxlength` | `number` | The maximum length of the pin input.`Default: 6` | | `onComplete` | `function`- (...args: any\[]) => void | A callback function that is called when the input is completely filled.`Default: undefined` | | `pasteTransformer` | `function`- (text: string) => string | A callback function that is called when the user pastes text into the input. It receives the pasted text as an argument and should return the sanitized text. Useful for cleaning up pasted text, like removing hyphens or other characters that should not make it into the input.`Default: undefined` | | `inputId` | `string` | Optionally provide an ID to apply to the hidden input element.`Default: undefined` | | `pushPasswordManagerStrategy` | `enum`- 'increase-width' \| 'none' | Enabled by default, it's an optional strategy for detecting Password Managers in the page and then shifting their badges to the right side, outside the input.`Default: undefined` | | `ref` $bindable | `HTMLDivElement` | The underlying DOM element being rendered. You can bind to this to get a reference to the element.`Default: undefined` | | `children` | `Snippet`- Snippet | The children content to render.`Default: undefined` | | `child` | `Snippet`- type SnippetProps = { props: Record\; }; | Use render delegation to render your own element. See [Child Snippet](/docs/child-snippet) docs for more information.`Default: undefined` | | Data Attribute | Value | Description | | -------------------------------------------------------------------------------------- | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | `data-pin-input-root` | `''` | Present on the root element. | ### PINInput.Cell A single cell of the pin input. | Property | Type | Description | | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `cell` | `object`- type Cell = { /\*\* The character displayed in the cell. \*/ char: string \| null \| undefined; /\*\* Whether the cell is active. \*/ isActive: boolean; /\*\* Whether the cell has a fake caret. \*/ hasFakeCaret: boolean; } | The cell object provided by the `cells` snippet prop from the `PinInput.Root` component.`Default: undefined` | | `ref` $bindable | `HTMLDivElement` | The underlying DOM element being rendered. You can bind to this to get a reference to the element.`Default: undefined` | | `children` | `Snippet` | The children content to render.`Default: undefined` | | `child` | `Snippet`- type SnippetProps = { props: Record\; }; | Use render delegation to render your own element. See [Child Snippet](/docs/child-snippet) docs for more information.`Default: undefined` | | Data Attribute | Value | Description | | ------------------------------------------------------------------------------ | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | `data-active` | `''` | Present when the cell is active. | | `data-inactive` | `''` | Present when the cell is inactive. | | `data-pin-input-cell` | `''` | Present on the cell element. |