{"id":12509,"library":"vue-input-otp","title":"Vue One-Time Passcode Input","description":"vue-input-otp is an accessible and unstyled Vue 3 component designed for capturing one-time passcodes (OTPs). It provides a flexible slot-based API, allowing developers complete control over the visual presentation of each digit input, rather than enforcing a specific UI. The library works by rendering an invisible native input that handles the underlying logic, while exposing slots for custom rendering. The current stable version is 0.3.2, with minor and patch releases occurring as needed. Its key differentiator is its 'bring-your-own-style' approach, offering maximum customization and robust accessibility features, including password manager support and precise control over virtual keyboard behavior on mobile devices. It aims to solve the lack of a native HTML OTP input by providing a robust, extensible solution for Vue applications.","status":"active","version":"0.3.2","language":"javascript","source_language":"en","source_url":"https://github.com/wobsoriano/vue-input-otp","tags":["javascript","vue","otp","input","accessible","typescript"],"install":[{"cmd":"npm install vue-input-otp","lang":"bash","label":"npm"},{"cmd":"yarn add vue-input-otp","lang":"bash","label":"yarn"},{"cmd":"pnpm add vue-input-otp","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Peer dependency required for a Vue 3 component.","package":"vue","optional":false}],"imports":[{"note":"OTPInput is a named export. Ensure to use curly braces for import. CommonJS `require` is not typically used for Vue SFC components or modern ESM-first libraries.","wrong":"import OTPInput from 'vue-input-otp'","symbol":"OTPInput","correct":"import { OTPInput } from 'vue-input-otp'"},{"note":"SlotProps is a TypeScript type. Use `import type` for type-only imports to ensure it's removed during compilation and avoid potential runtime issues or bundle size increases.","wrong":"import { SlotProps } from 'vue-input-otp'","symbol":"SlotProps","correct":"import type { SlotProps } from 'vue-input-otp'"},{"note":"Introduced in v0.3.0, this composable allows access to internal component states like focused and hovering for advanced slot customization. It is a named export.","symbol":"useVueOTPContext","correct":"import { useVueOTPContext } from 'vue-input-otp'"}],"quickstart":{"code":"<script setup lang=\"ts\">\nimport { ref } from 'vue';\nimport { OTPInput } from 'vue-input-otp';\n\nconst input = ref('123456');\n\n// Example Slot component (simplified for brevity, assume 'cn' utility and 'isActive' prop are defined elsewhere)\n// In a real app, you'd likely define this in a separate file, e.g., 'Slot.vue'\nconst Slot = {\n  props: ['char', 'isActive'],\n  template: `\n    <div\n      :class=\"[\n        'relative w-10 h-14 text-[2rem] flex items-center justify-center',\n        'transition-all duration-300 border-border border-y border-r first:border-l first:rounded-l-md last:rounded-r-md',\n        'group-hover:border-accent-foreground/20 group-focus-within:border-accent-foreground/20',\n        'outline outline-0 outline-accent-foreground/20',\n        { 'outline-4 outline-accent-foreground': isActive },\n      ]\"\n    >\n      <div v-if=\"char !== null\">{{ char }}</div>\n      <div v-if=\"char === null && isActive\" class=\"absolute pointer-events-none inset-0 flex items-center justify-center animate-caret-blink\">\n        <div class=\"w-px h-8 bg-white\" />\n      </div>\n    </div>\n  `\n};\n</script>\n\n<template>\n  <form class=\"flex flex-col gap-4 p-4\">\n    <label for=\"otp-input\" class=\"text-lg font-medium\">Enter OTP:</label>\n    <OTPInput\n      id=\"otp-input\"\n      v-slot=\"{ slots }\"\n      v-model=\"input\"\n      :maxlength=\"6\"\n      container-class=\"group flex items-center has-[:disabled]:opacity-30\"\n    >\n      <div class=\"flex\">\n        <Slot v-for=\"(slot, idx) in slots.slice(0, 3)\" v-bind=\"slot\" :key=\"idx\" />\n      </div>\n      <div class=\"flex w-10 justify-center items-center\">\n        <div class=\"w-3 h-1 rounded-full bg-border\" />\n      </div>\n      <div class=\"flex\">\n        <Slot v-for=\"(slot, idx) in slots.slice(3)\" v-bind=\"slot\" :key=\"idx\" />\n      </div>\n    </OTPInput>\n    <p class=\"mt-2 text-sm text-gray-600\">Current value: {{ input }}</p>\n  </form>\n</template>\n","lang":"typescript","description":"This quickstart demonstrates how to integrate `OTPInput` into a Vue 3 application, using `v-model` for two-way data binding and leveraging the slot props to render custom input fields, including a 'fake dash' separator, and local state management with `ref`."},"warnings":[{"fix":"Update event handlers to directly receive the value, e.g., `@input=\"handleInput\"` where `handleInput(value)` is your new function signature.","message":"The `input` event on the underlying native input now emits the raw value directly, rather than the event object. If you were listening for the event object, your handler will need to be updated.","severity":"breaking","affected_versions":">=0.2.0"},{"fix":"Implement custom validation logic using props or internal methods if a specific input pattern (e.g., only numbers) is required for your OTP fields.","message":"The default pattern for input validation was removed. This change provides more flexibility but requires users to implement their own validation if specific input patterns are needed.","severity":"breaking","affected_versions":">=0.3.1"},{"fix":"Utilize the provided slot props (e.g., `char`, `isActive`) to apply custom CSS classes and styles to each digit slot. Refer to the 'Default example' in the documentation for styling guidance, often using CSS frameworks like Tailwind CSS.","message":"vue-input-otp is intentionally unstyled. Developers are responsible for providing all visual styling for the OTP slots. Failure to do so will result in an invisible or poorly rendered input.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Set `pushPasswordManagerStrategy` to a suitable value (e.g., 'unshift' or 'shift') if you observe issues with password manager overlays. Consult the API reference for available strategies and their effects.","message":"To ensure proper functionality with password managers, especially those that inject badges, consider using the `pushPasswordManagerStrategy` prop. Incorrect handling can lead to visual glitches or obscured input.","severity":"gotcha","affected_versions":">=0.2.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Ensure you are passing a default slot to `OTPInput` that iterates over `slots` provided by the component's scope, as shown in the usage examples. E.g., `<OTPInput v-slot=\"{ slots }\">...</OTPInput>`.","cause":"The OTPInput component requires content in its default slot to render the individual OTP digits. If you don't provide a slot template, Vue doesn't know what to render inside the component.","error":"[Vue warn]: Component <OTPInput> is missing template or render function."},{"fix":"When defining your custom slot component, import `SlotProps` from `vue-input-otp` and use it to type your component's props. For example: `import type { SlotProps } from 'vue-input-otp'; defineProps<SlotProps>();`.","cause":"This error occurs in TypeScript when you're trying to access a property like `char` or `isActive` on a slot prop without correctly typing your slot component or props.","error":"Property 'char' does not exist on type 'SlotProps'."}],"ecosystem":"npm"}