PIN Input
A PIN Input plugin that allows to fill in data for inputs.
Contents
- Overview
- Installation
- Basic usage
- Configuration Options
- JavaScript API
- Events
- Common Patterns
- License
Overview
The PIN Input component provides a multi-field input interface for entering PIN codes, verification codes, or similar numeric/alphanumeric sequences. It automatically moves focus between fields and supports paste operations.
Key Features:
- Multiple input fields for PIN entry
- Automatic focus management
- Paste support for bulk entry
- Character validation via regex
- Programmatic control via JavaScript API
- Event system for completion tracking
- Accessibility support
Installation
To get started, install PIN Input plugin via npm, else you can skip this step if you are already using Preline UI as a package.
npm i @preline/pin-input
CSS
Use @source to register the plugin's JavaScript path for Tailwind CSS scanning, then @import the plugin's CSS files into your Tailwind CSS file.
@import "tailwindcss";
/* @preline/pin-input */
@source "../node_modules/@preline/pin-input/*.js";
@import "./node_modules/@preline/pin-input/variants.css";
@import "./node_modules/@preline/pin-input/theme.css";
JavaScript
Include the JavaScript that powers the interactive elements near the end of your </body> tag:
<script src="./node_modules/@preline/pin-input/index.js"></script>
Manual Initialization
Use the non-auto entry if you need manual initialization. In this mode, automatic initialization on page load is not included, so the component should be initialized explicitly.
<script type="module">
import HSPinInput from "@preline/pin-input/non-auto.mjs";
new HSPinInput(document.querySelector("#pin-input"));
</script>
Via Bundler
When using a bundler (Vite, webpack, etc.), import the plugin directly as an ES module.
@preline/pin-input is the auto-init entry: it scans the DOM and initializes matching elements automatically.
import "@preline/pin-input";
@preline/pin-input/non-auto is the manual entry: use it when you want explicit control over when initialization happens, either via autoInit() or by creating a specific instance yourself.
import HSPinInput from "@preline/pin-input/non-auto";
HSPinInput.autoInit();
// Or initialize a specific element manually
const el = document.querySelector("#pin-input");
if (el) new HSPinInput(el);
TypeScript
This package ships with TypeScript type definitions. No additional @types/ package is needed.
Basic usage
The following example demonstrates the minimal HTML structure required for a PIN input component. This is a base template without custom styling - you can apply your own CSS classes and styles as needed. The component consists of multiple input fields that automatically advance focus.
<div data-hs-pin-input>
<input type="text" data-hs-pin-input-item>
<input type="text" data-hs-pin-input-item>
<input type="text" data-hs-pin-input-item>
<input type="text" data-hs-pin-input-item>
</div>
Structure Requirements:
data-hs-pin-input: Required on the container elementdata-hs-pin-input-item: Required on each input field- All input fields should be direct children of the container
Initial State:
- Input fields are empty by default
- Focus starts on the first input field (if
autofocusclass is used)
Configuration Options
Data Options
Data options are specified in the data-hs-pin-input attribute.
| Attribute | Target Element | Type | Default | Description |
|---|---|---|---|---|
data-hs-pin-input |
Container | - | - | Activate a Pin Input by specifying on an element. Should be added to the container. |
:availableCharsRE |
Inside data-hs-pin-input |
RegExp (string) | "^[a-zA-Z0-9]+$" |
Regular expression string for available characters. Only characters matching this regex will be accepted. |
data-hs-pin-input-item |
Input element | - | - | Determines which element inside the initialized container will be responsible for entering data. Should be added to the input. |
Example:
<div data-hs-pin-input='{
"availableCharsRE": "^[0-9]+$"
}'>
<!-- Input fields -->
</div>
CSS Classes (Modifiers)
CSS class modifiers use Tailwind-style syntax with -- prefix to control PIN input behavior.
| Class | Required On | Purpose |
|---|---|---|
autofocus |
One of the input fields | If one of the fields has this class, it will be focused when the page loads. |
Tailwind Modifiers
| Name | Description |
|---|---|
hs-pin-input-active:* |
The class is added to the input when the PIN has been set up (all fields are filled). |
JavaScript API
The HSPinInput object is available in the global window object after the plugin is loaded.
Instance Methods
These methods are called on a PIN input instance.
| Method | Parameters | Return Type | Description |
|---|---|---|---|
destroy() |
None | void |
Destroys the PIN input instance, removes all generated markup, classes, and event listeners. Use when removing PIN input from DOM. |
Static Methods
These methods are called directly on the HSPinInput class.
| Method | Parameters | Return Type | Description |
|---|---|---|---|
HSPinInput.getInstance(target, isInstance) |
target: HTMLElement | string (CSS selector)isInstance: boolean (optional) |
HSPinInput | { id: string | number, element: HSPinInput } | null |
Returns the PIN input instance associated with the target. If isInstance is true, returns collection item object { id, element } where element is the HSPinInput instance. If isInstance is false or omitted, returns the HSPinInput instance directly. Returns null if PIN input instance is not found. |
Usage Examples
Example 1: Destroying PIN input instance
const instance = HSPinInput.getInstance('#hs-pin-input', true);
if (instance) {
const { element } = instance;
const destroyBtn = document.querySelector('#hs-destroy-btn');
destroyBtn.addEventListener('click', () => {
element.destroy();
});
}
Example 2: Getting instance and accessing properties
// Get the PIN input instance
const instance = HSPinInput.getInstance('#hs-pin-input', true);
if (instance) {
const { element } = instance;
// Access instance properties
console.log('Current value:', element.currentValue);
console.log('Items:', element.items);
// Clean up when removing from DOM
function removePinInput() {
element.destroy();
}
}
Example 3: Destroying PIN input instance
const instance = HSPinInput.getInstance('#hs-pin-input', true);
if (instance) {
const { element } = instance;
const removeBtn = document.querySelector('#hs-remove-btn');
removeBtn.addEventListener('click', () => {
// Clean up before removing from DOM
element.destroy();
// Now safe to remove the element
document.querySelector('#hs-pin-input').remove();
});
}
Events
PIN input instances emit events that can be listened to for completion tracking and custom behavior.
| Event Name | When Fired | Callback Parameter | Description |
|---|---|---|---|
on:completed |
When the PIN has been set up (all fields filled) | { currentValue: string } |
Fires when all input fields have been filled. Returns an object with the currentValue containing the complete PIN string. |
Event Usage Example
// Get PIN input instance
const instance = HSPinInput.getInstance('#hs-pin-input', true);
if (instance) {
const { element } = instance;
// Listen to completed event
element.on('completed', ({ currentValue }) => {
console.log('PIN completed:', currentValue);
// Perform actions after PIN is completed
// e.g., validate PIN, submit form, proceed to next step
});
}
Common Patterns
Pattern 1: Numeric PIN Only
Restrict input to numbers only.
<div data-hs-pin-input='{
"availableCharsRE": "^[0-9]+$"
}'>
<input type="text" data-hs-pin-input-item>
<input type="text" data-hs-pin-input-item>
<input type="text" data-hs-pin-input-item>
<input type="text" data-hs-pin-input-item>
</div>
Pattern 2: Auto-focus First Field
Automatically focus the first field on page load.
<div data-hs-pin-input>
<input type="text" data-hs-pin-input-item class="autofocus">
<input type="text" data-hs-pin-input-item>
<input type="text" data-hs-pin-input-item>
<input type="text" data-hs-pin-input-item>
</div>
Pattern 3: Handling Completion
Handle PIN completion with event listener.
<div id="hs-pin-input-first" data-hs-pin-input>
<input type="text" data-hs-pin-input-item>
<input type="text" data-hs-pin-input-item>
<input type="text" data-hs-pin-input-item>
<input type="text" data-hs-pin-input-item>
</div>
<script>
const instance = HSPinInput.getInstance('#hs-pin-input-first', true);
if (instance) {
const { element } = instance;
element.on('completed', ({ currentValue }) => {
console.log('PIN entered:', currentValue);
// Validate or submit the PIN
});
}
</script>
License
Copyright (c) 2024 Htmlstream.
Licensed under the MIT License.