
Security News
The Code You Didn't Write Is Still Yours to Defend
AI agents are pulling packages into environments no scanner is watching, creating exposure before security teams can see it.
svelte-otp-input
Advanced tools
Flexible OTP/verification code input component for Svelte 5+ with full customization, mobile support, 2FA/MFA authentication, and accessibility features
A flexible and customizable One-Time Password (OTP) input component for Svelte 5+. Perfect for authentication flows, verification codes, 2FA (two-factor authentication), MFA (multi-factor authentication), PIN codes, and secure login experiences in your Svelte applications.
Looking for a Svelte 5 OTP component, verification code input, or 2FA input field? This package provides everything you need for modern authentication flows:
Use Cases: One-time passwords (OTP), email/SMS verification codes, two-factor authentication (2FA), multi-factor authentication (MFA), PIN code entry, secure access codes, payment verification, and more.
npm install svelte-otp-input
pnpm add svelte-otp-input
yarn add svelte-otp-input
Get up and running in seconds:
<script>
import OtpInput from 'svelte-otp-input';
let code = $state("");
</script>
<OtpInput
bind:value={code}
numInputs={6}
onComplete={(otp) => {
console.log('OTP entered:', otp);
// Verify OTP with your backend
}}
/>
That's it! See the full documentation for advanced features and customization options.
| Prop | Type | Description |
|---|---|---|
numInputs | number | Number of OTP input boxes (must be a positive integer) |
value | string | The OTP value (bindable with bind:value) |
| Prop | Type | Default | Description |
|---|---|---|---|
inputType | string | "number" | Input type: "number", "text", "password", "upper-alnum", "uppercase", "lower-alnum", "lowercase", "alnum", or custom regex |
separator | string | string[] | snippet | "-" | Character(s) or snippet between inputs |
groupSeparator | string | snippet | " " | Separator between groups (when using group prop) |
group | number[] | null | Array defining input grouping (e.g., [3, 3] for 6 inputs split into two groups) |
shouldAutoFocus | boolean | true | Auto-focus first input on component mount |
placeholder | string | "" | Placeholder text for empty inputs |
isError | boolean | false | Show error state styling |
isDisabled | boolean | false | Disable all inputs |
restrictPaste | boolean | false | Prevent paste functionality for enhanced security |
| Prop | Type | Default | Description |
|---|---|---|---|
containerStyle | string | object | "" | Styles for the container wrapper |
inputStyles | string | object | Array<string | object> | "" | Styles for input boxes (supports Tailwind classes, CSS objects, or global styles) |
inputFocusStyle | string | object | "" | Styles applied when input is focused |
inputErrorStyle | string | object | Array<string | object> | "" | Styles applied when isError is true |
inputDisabledStyle | string | object | Array<string | object> | "" | Styles applied when inputs are disabled |
placeholderStyle | string | object | "" | Styles for placeholder text |
stylePriority | object | See below | Control which styles take precedence |
Default Style Priority:
{
inputDisabledStyle: 'p0', // Highest priority
inputErrorStyle: 'p1',
inputFocusStyle: 'p2' // Lowest priority
}
| Prop | Type | Description |
|---|---|---|
onComplete | (value: string) => void | Called when all inputs are filled |
onEnter | (value: string) => void | Called when Enter key is pressed |
onInput | (event, index) => void | Called on input change for each character |
onFocus | (event, index) => void | Called when an input receives focus |
onBlur | (event, index) => void | Called when an input loses focus |
onPaste | (event, index) => void | Called on paste event |
keyDown | (event, index) => void | Called on key down event |
| Prop | Type | Description |
|---|---|---|
inputRef | Array | Pass your own $state(Array(numInputs).fill(null)) to access input element references |
Perfect for simple verification codes:
<script>
import OtpInput from 'svelte-otp-input';
let otp = $state("");
</script>
<OtpInput
bind:value={otp}
numInputs={4}
placeholder="0"
/>
Commonly used for SMS verification and 2FA:
<script>
let otp = $state("");
</script>
<OtpInput
bind:value={otp}
numInputs={6}
group={[3, 3]}
groupSeparator="—"
/>
<p>Entered OTP: {otp}</p>
Create a beautiful, modern OTP input:
<OtpInput
bind:value={otp}
numInputs={4}
containerStyle="flex gap-4 justify-center py-8"
inputStyles="w-14 h-14 text-2xl font-bold text-center border-2 border-gray-300 rounded-lg"
inputFocusStyle="border-blue-500 ring-2 ring-blue-200 outline-none"
inputErrorStyle="border-red-500 bg-red-50"
/>
For precise control over appearance:
<OtpInput
bind:value={otp}
numInputs={4}
containerStyle={{
gap: '16px',
padding: '20px',
justifyContent: 'center'
}}
inputStyles={{
width: '60px',
height: '60px',
fontSize: '24px',
fontWeight: 'bold',
textAlign: 'center',
borderRadius: '8px',
border: '2px solid #e0e0e0',
backgroundColor: '#ffffff'
}}
inputFocusStyle={{
border: '2px solid #4CAF50',
boxShadow: '0 0 8px rgba(76, 175, 80, 0.3)',
outline: 'none'
}}
/>
Validate OTP and show errors:
<script>
import OtpInput from 'svelte-otp-input';
let otp = $state("");
let hasError = $state(false);
let isVerifying = $state(false);
async function handleComplete(value) {
isVerifying = true;
// Simulate API call
const isValid = await verifyOTP(value);
if (!isValid) {
hasError = true;
// Reset after showing error
setTimeout(() => {
otp = "";
hasError = false;
}, 2000);
} else {
hasError = false;
console.log("OTP verified successfully!");
}
isVerifying = false;
}
async function verifyOTP(code) {
// Your verification logic
return code === "123456";
}
</script>
<OtpInput
bind:value={otp}
numInputs={6}
isError={hasError}
isDisabled={isVerifying}
onComplete={handleComplete}
inputErrorStyle="border-red-500 bg-red-50 text-red-900"
/>
{#if hasError}
<p class="text-red-500 mt-2">Invalid OTP. Please try again.</p>
{/if}
{#if isVerifying}
<p class="text-gray-500 mt-2">Verifying...</p>
{/if}
For secure PIN entry:
<OtpInput
bind:value={otp}
numInputs={6}
inputType="password"
placeholder="•"
/>
Different separators between inputs:
<OtpInput
bind:value={otp}
numInputs={5}
separator={['-', '-', ' ', '-']}
/>
<!-- Renders as: X-X-X X-X -->
For alphabetic verification codes:
<OtpInput
bind:value={otp}
numInputs={4}
inputType="uppercase"
placeholder="A"
/>
For mixed character codes:
<OtpInput
bind:value={otp}
numInputs={8}
inputType="alnum"
group={[4, 4]}
groupSeparator=" - "
/>
Programmatically control inputs:
<script>
import OtpInput from 'svelte-otp-input';
let otp = $state("");
let inputRefs = $state(Array(6).fill(null));
function focusThirdInput() {
inputRefs[2]?.focus();
}
function clearAndFocusFirst() {
otp = "";
inputRefs[0]?.focus();
}
</script>
<OtpInput
bind:value={otp}
numInputs={6}
inputRef={inputRefs}
/>
<div class="mt-4 space-x-2">
<button onclick={focusThirdInput}>
Focus 3rd Input
</button>
<button onclick={clearAndFocusFirst}>
Clear & Reset
</button>
</div>
Submit on Enter key press:
<script>
let otp = $state("");
function handleEnter(value) {
if (value.length === 6) {
console.log("Submitting OTP:", value);
// Submit to your backend
}
}
</script>
<OtpInput
bind:value={otp}
numInputs={6}
onEnter={handleEnter}
/>
<p class="text-sm text-gray-500 mt-2">
Press Enter to submit
</p>
Prevent users from pasting codes:
<OtpInput
bind:value={otp}
numInputs={6}
restrictPaste={true}
/>
<p class="text-sm text-gray-500 mt-2">
Please enter each digit manually
</p>
The component supports various input types for different use cases:
| Type | Description | Allowed Characters | Example |
|---|---|---|---|
"number" | Numeric only | 0-9 | 1234 |
"text" | Any text | All characters | abcd |
"password" | Masked input | All characters | •••• |
"upper-alnum" | Uppercase alphanumeric | A-Z, 0-9 | A1B2 |
"uppercase" | Uppercase letters only | A-Z | ABCD |
"lower-alnum" | Lowercase alphanumeric | a-z, 0-9 | a1b2 |
"lowercase" | Lowercase letters only | a-z | abcd |
"alnum" | Alphanumeric (any case) | a-z, A-Z, 0-9 | Ab12 |
| Custom Regex | Custom pattern | Defined by your regex | Variable |
let regex = ^[A-F0-9]$
<OtpInput
bind:value={otp}
numInputs={4}
inputType={regex}
/>
<!-- Only accepts hexadecimal characters -->
Full keyboard support for accessibility:
onEnter callbackrestrictPaste is enabled)<OtpInput
bind:value={otp}
numInputs={6}
containerStyle="flex gap-3 p-6 bg-gray-50 rounded-xl"
inputStyles="w-12 h-12 text-xl font-semibold text-center border-2 border-gray-300 rounded-lg transition-all duration-200"
inputFocusStyle="border-blue-500 ring-4 ring-blue-100 scale-105"
inputErrorStyle="border-red-500 bg-red-50"
/>
<OtpInput
bind:value={otp}
numInputs={4}
inputStyles={{
width: '3rem',
height: '3rem',
fontSize: '1.5rem',
textAlign: 'center',
border: '2px solid #e5e7eb',
borderRadius: '0.5rem',
transition: 'all 0.2s'
}}
inputFocusStyle={{
borderColor: '#3b82f6',
boxShadow: '0 0 0 3px rgba(59, 130, 246, 0.1)'
}}
/>
<OtpInput
bind:value={otp}
numInputs={6}
inputStyles="otp-input"
/>
<style>
:global(.otp-input) {
width: 3rem;
height: 3rem;
font-size: 1.5rem;
text-align: center;
border: 2px solid #e5e7eb;
border-radius: 0.5rem;
transition: all 0.2s ease;
}
:global(.otp-input:focus) {
border-color: #3b82f6;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
outline: none;
}
</style>
Yes! This component is built specifically for Svelte 5+ using modern runes ($state, $derived, etc.). It will not work with Svelte 4 or earlier versions.
Absolutely! The component supports mobile SMS autocomplete. On supported mobile browsers, users can tap to auto-fill the OTP from incoming SMS messages.
Yes! The component includes:
Completely! You can use:
:global() modifierUse the onComplete callback to validate when all digits are entered:
<OtpInput
bind:value={otp}
numInputs={6}
onComplete={async (code) => {
const isValid = await verifyWithBackend(code);
if (!isValid) {
// Handle invalid OTP
}
}}
/>
Yes! Simply bind the value and reset it:
<script>
import OtpInput, { setValue } from 'svelte-otp-input'
let otp = $state("");
function clearOTP() {
setValue("")
}
</script>
<OtpInput bind:value={otp} numInputs={6} />
<button onclick={clearOTP}>Clear</button>
Yes! The component is fully mobile-optimized with:
By default, pasting is enabled and will auto-fill all inputs. To disable:
<OtpInput
bind:value={otp}
numInputs={6}
restrictPaste={true}
/>
You can also use the onPaste callback to customize paste behavior.
Yes! You can use:
separator="-"separator={['-', '-', ' ', '-']}separator={customSnippet}<OtpInput
bind:value={pin}
numInputs={4}
inputType="password"
placeholder="•"
/>
Requirements: Svelte 5+
Contributions are welcome! Here's how you can help:
# Clone the repository
git clone https://github.com/yourusername/svelte-otp-input.git
# Install dependencies
npm install
# Run development server
npm run dev
# Run tests
npm test
# Build for production
npm run build
MIT © [Your Name]
See LICENSE for details.
Built with ❤️ for the Svelte community.
Keywords: svelte otp, svelte 5 otp input, svelte verification code, svelte 2fa input, svelte mfa, svelte pin code, svelte authentication component, one-time password svelte, verification input svelte, svelte security input, svelte otp component, two-factor authentication svelte, multi-factor authentication svelte, svelte sms verification, svelte code input
Made for Svelte 5+ | Zero Dependencies | Production Ready
FAQs
Flexible OTP/verification code input component for Svelte 5+ with full customization, mobile support, 2FA/MFA authentication, and accessibility features
The npm package svelte-otp-input receives a total of 35 weekly downloads. As such, svelte-otp-input popularity was classified as not popular.
We found that svelte-otp-input demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
AI agents are pulling packages into environments no scanner is watching, creating exposure before security teams can see it.

Security News
GitHub Actions checkout now blocks risky pull_request_target checkouts by default to help prevent pwn request supply chain attacks.

Product
Socket now supports Custom Roles and Repository Access Permissions so organizations can control who can access specific repositories and actions.