Declarative pin code component for Svelte.
A pin code is a short sequence of characters (usually numeric) used for verification. It differs from a password in that it is typically ephemeral and is not predetermined by the user.
Try it in the Svelte REPL.
# npm
npm i -D svelte-pincode
# pnpm
pnpm i -D svelte-pincode
# Bun
bun i -D svelte-pincode
# Yarn
yarn add -D svelte-pincode
Bind to either the code
or value
prop.
string[]
): Array of input values. An empty string represents an undefined value.string
): code
joined as a string.<script>
import { Pincode, PincodeInput } from "svelte-pincode";
let code = [];
let value = '';
</script>
<Pincode bind:code bind:value>
<PincodeInput />
<PincodeInput />
<PincodeInput />
<PincodeInput />
</Pincode>
<div>code: <code>{JSON.stringify(code)}</code></div>
<div>value: <code>{JSON.stringify(value)}</code></div>
Set selectTextOnFocus
to true
for the input value text to be selected when focused.
<script>
import { Pincode, PincodeInput } from "svelte-pincode";
let input;
</script>
<Pincode selectTextOnFocus>
<PincodeInput bind:ref={input} value="0" />
<PincodeInput />
<PincodeInput />
<PincodeInput />
</Pincode>
<button on:click={() => input.focus()}>
Focus input
</button>
By default, this component accepts alphanumeric values.
Set type
to "numeric"
to only allow numbers.
<Pincode type="numeric">
<PincodeInput />
<PincodeInput />
<PincodeInput />
<PincodeInput />
</Pincode>
Define intitial input values by using the code
prop or value
prop on PincodeInput
.
<script>
import { Pincode, PincodeInput } from "svelte-pincode";
let pincode = ["1", "", "3"];
</script>
<Pincode bind:code={pincode}>
<PincodeInput />
<PincodeInput value="2" />
<PincodeInput />
<PincodeInput />
</Pincode>
<div>code: <code>{JSON.stringify(pincode)}</code></div>
Actual validation is left to the consumer.
This example illustrates how you can validate the code once all inputs have a value by binding to the complete
prop.
<script>
import { Pincode, PincodeInput } from "svelte-pincode";
const correctCode = "1234";
let inputValue = '';
let complete = false;
$: success = complete && inputValue === correctCode;
$: error = complete && !success;
</script>
<Pincode bind:complete bind:value={inputValue}>
<PincodeInput />
<PincodeInput />
<PincodeInput />
<PincodeInput />
</Pincode>
<div class:complete class:success class:error>
{#if !complete}
Enter {correctCode.length - inputValue.length} more digit(s)...
{/if}
{#if success}Correct code{/if}
{#if error}Incorrect code{/if}
</div>
Use the dispatched "complete" event as an alternative to binding the complete
prop.
<Pincode
on:complete="{(e) => {
console.log(e.detail); // { code: string[]; value: string; }
}}"
/>
code
can be set programmatically.
In the following example, type some initial values and try setting or clearing the code.
<script>
import { Pincode, PincodeInput } from "svelte-pincode";
let passcode = [];
</script>
<Pincode bind:code={passcode}>
<PincodeInput />
<PincodeInput />
<PincodeInput />
<PincodeInput />
</Pincode>
<div>code: <code>{JSON.stringify(passcode)}</code></div>
<button on:click={() => passcode = ['1', '2', '3', '4']}>
Set code
</button>
<button on:click={() => passcode = ['', '', '', '']}>
Clear code
</button>
To programmatically focus the first input, invoke the focusFirstInput
method in a component reference.
<script>
import { Pincode, PincodeInput } from "svelte-pincode";
let ref;
</script>
<Pincode bind:this={ref}>
<PincodeInput />
<PincodeInput />
<PincodeInput />
<PincodeInput />
</Pincode>
<button on:click={ref.focusFirstInput}>
Focus first input
</button>
To focus the next input with no value, invoke the focusNextEmptyInput
method.
<script>
import { Pincode, PincodeInput } from "svelte-pincode";
let pincodeRef;
</script>
<Pincode code={["9", "9"]} bind:this={pincodeRef}>
<PincodeInput />
<PincodeInput />
<PincodeInput />
<PincodeInput />
</Pincode>
<button on:click={pincodeRef.focusNextEmptyInput}>
Focus next empty input
</button>
To focus the last input, invoke the focusLastInput
method.
<script>
import { Pincode, PincodeInput } from "svelte-pincode";
let passcodeRef;
</script>
<Pincode bind:this={passcodeRef}>
<PincodeInput />
<PincodeInput />
<PincodeInput />
<PincodeInput />
</Pincode>
<button on:click={passcodeRef.focusLastInput}>
Focus last input
</button>
This component is minimally styled; override the default styles by targeting the data-pincode
selector:
/** Pincode **/
:global([data-pincode]) {
display: inline-flex;
border: 1px solid #e0e0e0;
}
/** PincodeInput */
:global([data-pincode] input) {
width: 3rem;
padding: 0.5rem 1rem;
margin: 0;
border: 0;
border-radius: 0;
text-align: center;
}
:global([data-pincode] input:focus) {
z-index: 1;
}
:global([data-pincode] input:not(:last-of-type)) {
border-right: 1px solid #e0e0e0;
}
Use the unstyled components located in the svelte-pincode/unstyled
folder if you prefer to style the components from scratch.
<script>
import Pincode from "svelte-pincode/unstyled/Pincode.svelte";
import PincodeInput from "svelte-pincode/unstyled/PincodeInput.svelte";
</script>
Name | Type | Default value |
---|---|---|
code | string[] |
[] |
value | string |
"" |
type | "alphanumeric" or "numeric" |
"alphanumeric" |
selectTextOnFocus | boolean |
false |
focusFirstInput
focusNextEmptyInput
focusLastInput
<Pincode
on:complete="{(e) => {
console.log(e.detail); // { code: string[]; value: string; }
}}"
on:clear
/>
Name | Type | Default value |
---|---|---|
id | string |
"input" + Math.random().toString(36) |
ref | HTMLInputElement |
null |