🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

svelte-otp-input

Package Overview
Dependencies
Maintainers
1
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

svelte-otp-input

Flexible OTP/verification code input component for Svelte 5+ with full customization, mobile support, 2FA/MFA authentication, and accessibility features

latest
Source
npmnpm
Version
0.1.6
Version published
Weekly downloads
45
-8.16%
Maintainers
1
Weekly downloads
 
Created
Source

Svelte OTP Input

npm version License: MIT Downloads

Svelte OTP Input Logo

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.

📚 View Detailed Documentation

Why Choose Svelte OTP Input?

Looking for a Svelte 5 OTP component, verification code input, or 2FA input field? This package provides everything you need for modern authentication flows:

  • Svelte 5 Native: Built specifically for Svelte 5+ with runes support ($state, $derived)
  • Zero Dependencies: Lightweight and performant - no bloat
  • Production Ready: Battle-tested in real-world applications
  • Mobile First: Optimized for touch devices with SMS autocomplete support
  • Fully Accessible: ARIA labels and complete keyboard navigation
  • Highly Customizable: Style with Tailwind, CSS objects, or global styles

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.

Features

  • 🎯 Flexible Input Types: Support for numbers, text, passwords, alphanumeric inputs, uppercase/lowercase, and custom regex patterns
  • 🎨 Fully Customizable: Control styles, separators, placeholders, focus states, error states, and disabled states
  • 📱 Mobile Optimized: Auto-complete support for SMS OTP codes and mobile-friendly interactions
  • Accessible: WCAG compliant with ARIA labels and complete keyboard navigation support
  • 🎭 Error States: Built-in error styling and validation with customizable error appearance
  • 🔒 Paste Protection: Optional paste restriction for enhanced security
  • 📦 Grouping Support: Group inputs with custom separators (e.g., 3-3 format for 6-digit codes)
  • 🎪 Snippet Support: Use Svelte 5 snippets for fully custom separators
  • 🎮 Programmatic Control: Access and control individual inputs via refs
  • Lightweight: Minimal bundle size impact on your application

Installation

npm install svelte-otp-input
pnpm add svelte-otp-input
yarn add svelte-otp-input

Quick Start

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.

Props

Required Props

PropTypeDescription
numInputsnumberNumber of OTP input boxes (must be a positive integer)
valuestringThe OTP value (bindable with bind:value)

Optional Props

PropTypeDefaultDescription
inputTypestring"number"Input type: "number", "text", "password", "upper-alnum", "uppercase", "lower-alnum", "lowercase", "alnum", or custom regex
separatorstring | string[] | snippet"-"Character(s) or snippet between inputs
groupSeparatorstring | snippet" "Separator between groups (when using group prop)
groupnumber[]nullArray defining input grouping (e.g., [3, 3] for 6 inputs split into two groups)
shouldAutoFocusbooleantrueAuto-focus first input on component mount
placeholderstring""Placeholder text for empty inputs
isErrorbooleanfalseShow error state styling
isDisabledbooleanfalseDisable all inputs
restrictPastebooleanfalsePrevent paste functionality for enhanced security

Styling Props

PropTypeDefaultDescription
containerStylestring | object""Styles for the container wrapper
inputStylesstring | object | Array<string | object>""Styles for input boxes (supports Tailwind classes, CSS objects, or global styles)
inputFocusStylestring | object""Styles applied when input is focused
inputErrorStylestring | object | Array<string | object>""Styles applied when isError is true
inputDisabledStylestring | object | Array<string | object>""Styles applied when inputs are disabled
placeholderStylestring | object""Styles for placeholder text
stylePriorityobjectSee belowControl which styles take precedence

Default Style Priority:

{
  inputDisabledStyle: 'p0', // Highest priority
  inputErrorStyle: 'p1',
  inputFocusStyle: 'p2'     // Lowest priority
}

Callback Props

PropTypeDescription
onComplete(value: string) => voidCalled when all inputs are filled
onEnter(value: string) => voidCalled when Enter key is pressed
onInput(event, index) => voidCalled on input change for each character
onFocus(event, index) => voidCalled when an input receives focus
onBlur(event, index) => voidCalled when an input loses focus
onPaste(event, index) => voidCalled on paste event
keyDown(event, index) => voidCalled on key down event

Advanced Props

PropTypeDescription
inputRefArrayPass your own $state(Array(numInputs).fill(null)) to access input element references

Examples

Basic 4-Digit OTP

Perfect for simple verification codes:

<script>
  import OtpInput from 'svelte-otp-input';
  
  let otp = $state("");
</script>

<OtpInput
  bind:value={otp}
  numInputs={4}
  placeholder="0"
/>

6-Digit OTP with Grouping

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>

Custom Styling with Tailwind

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"
/>

Custom Styling with CSS Objects

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'
  }}
/>

With Error State and Validation

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}

Password Input Type

For secure PIN entry:

<OtpInput
  bind:value={otp}
  numInputs={6}
  inputType="password"
  placeholder="•"
/>

With Custom Separators (Array)

Different separators between inputs:

<OtpInput
  bind:value={otp}
  numInputs={5}
  separator={['-', '-', ' ', '-']}
/>
<!-- Renders as: X-X-X X-X -->

Uppercase Letters Only

For alphabetic verification codes:

<OtpInput
  bind:value={otp}
  numInputs={4}
  inputType="uppercase"
  placeholder="A"
/>

Alphanumeric Input

For mixed character codes:

<OtpInput
  bind:value={otp}
  numInputs={8}
  inputType="alnum"
  group={[4, 4]}
  groupSeparator=" - "
/>

Access Input References

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>

With Enter Key Handler

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>

Disable Paste for Security

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>

Input Types

The component supports various input types for different use cases:

TypeDescriptionAllowed CharactersExample
"number"Numeric only0-91234
"text"Any textAll charactersabcd
"password"Masked inputAll characters••••
"upper-alnum"Uppercase alphanumericA-Z, 0-9A1B2
"uppercase"Uppercase letters onlyA-ZABCD
"lower-alnum"Lowercase alphanumerica-z, 0-9a1b2
"lowercase"Lowercase letters onlya-zabcd
"alnum"Alphanumeric (any case)a-z, A-Z, 0-9Ab12
Custom RegexCustom patternDefined by your regexVariable

Using Custom Regex

let regex = ^[A-F0-9]$

<OtpInput
  bind:value={otp}
  numInputs={4}
  inputType={regex}
/>
<!-- Only accepts hexadecimal characters -->

Keyboard Navigation

Full keyboard support for accessibility:

  • Left Arrow / Right Arrow: Navigate between inputs
  • Backspace: Delete current character and move to previous input
  • Tab / Shift+Tab: Move to next/previous input or form element
  • Enter: Trigger onEnter callback
  • Paste (Ctrl+V / Cmd+V): Auto-fill all inputs from clipboard (unless restrictPaste is enabled)
  • Number keys: Direct input of digits

Styling Guide

Using Tailwind CSS Classes

<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"
/>

Using CSS Objects

<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)'
  }}
/>

Using Global CSS (with :global())

<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>

Frequently Asked Questions

Does this work with Svelte 5?

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.

Can I use this for SMS verification codes?

Absolutely! The component supports mobile SMS autocomplete. On supported mobile browsers, users can tap to auto-fill the OTP from incoming SMS messages.

Is it accessible?

Yes! The component includes:

  • Proper ARIA labels for screen readers
  • Full keyboard navigation support
  • Focus management
  • High contrast support
  • Keyboard-only operation

Can I customize the styling?

Completely! You can use:

  • Tailwind CSS utility classes
  • Global CSS with the :global() modifier
  • Mix and match different styling approaches

How do I validate the OTP?

Use 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
    }
  }}
/>

Can I clear the OTP programmatically?

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>

Does it work on mobile devices?

Yes! The component is fully mobile-optimized with:

  • Touch-friendly input sizes
  • Native keyboard support (numeric, text, etc.)
  • SMS autocomplete on supported devices
  • Responsive design

How do I handle paste events?

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.

Can I use custom separators?

Yes! You can use:

  • Single character: separator="-"
  • Array of separators: separator={['-', '-', ' ', '-']}
  • Svelte snippet: separator={customSnippet}

How do I create a PIN code input?

<OtpInput
  bind:value={pin}
  numInputs={4}
  inputType="password"
  placeholder="•"
/>

Browser Support

  • ✅ Chrome/Edge (latest)
  • ✅ Firefox (latest)
  • ✅ Safari (latest)
  • ✅ Mobile browsers (iOS Safari, Chrome Mobile)
  • ✅ Modern browsers with ES2020+ support

Requirements: Svelte 5+

Contributing

Contributions are welcome! Here's how you can help:

  • 🐛 Report bugs: Open an issue with details and reproduction steps
  • 💡 Suggest features: Share your ideas in discussions
  • 🔧 Submit PRs: Fork, create a feature branch, and submit a pull request
  • 📖 Improve docs: Help make the documentation better
  • Star the repo: Show your support!

Development Setup

# 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

License

MIT © [Your Name]

See LICENSE for details.

Support

Acknowledgments

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

Keywords

svelte

FAQs

Package last updated on 25 Oct 2025

Did you know?

Socket

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.

Install

Related posts