Skip to content

Pin Input

Alpha
A sequence of one-character alphanumeric inputs.
vue
<script setup lang="ts">
import { ref } from 'vue'
import { Label, PinInputInput, PinInputRoot } from 'radix-vue'

const value = ref<string[]>([])
function handleComplete(e: string[]) {
  // eslint-disable-next-line no-alert
  alert(e.join(''))
}
</script>

<template>
  <div>
    <Label for="pin-input" class="text-white">Pin Input</Label>
    <PinInputRoot
      id="pin-input"
      v-model="value"
      placeholder=""
      class="flex gap-2 items-center mt-1"
      @complete="handleComplete"
    >
      <PinInputInput
        v-for="(id, index) in 5"
        :key="id"
        :index="index"
        class="w-10 h-10 bg-white rounded text-center shadow-lg text-green10 placeholder:text-mauve8 focus:outline focus:outline-2 focus:outline-offset-2 focus:outline-white"
      />
    </PinInputRoot>
  </div>
</template>

Features

  • Full keyboard navigation.
  • Can be controlled or uncontrolled.
  • Supports pasting from clipboard
  • Emit event when inputs were filled.

Installation

Install the component from your command line.

sh
$ npm add radix-vue

Anatomy

Import all parts and piece them together.

vue
<script setup>
import { PinInputInput, PinInputRoot } from 'radix-vue'
</script>

<template>
  <PinInputRoot>
    <PinInputInput />
  </PinInputRoot>
</template>

API Reference

Root

Contains all the parts of a checkbox. An input will also render when used within a form to ensure events propagate correctly.

PropDefaultType
as
'div'
AsTag | Component

The element or component this component should render as. Can be overwrite by asChild

asChild
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

defaultValue
string[]

The default value of the pin inputs when it is initially rendered. Use when you do not need to control its checked state.

dir
'ltr' | 'rtl'

The reading direction of the combobox when applicable.
If omitted, inherits globally from DirectionProvider or assumes LTR (left-to-right) reading mode.

disabled
boolean

When true, prevents the user from interacting with the pin input

id
string

Id of the element

mask
boolean

When true, pin inputs will be treated as password.

modelValue
string[]

The controlled checked state of the pin input. Can be binded as v-model.

name
string

The name of the pin input. Submitted with its owning form as part of a name/value pair.

otp
boolean

When true, mobile devices will autodetect the OTP from messages or clipboard, and enable the autocomplete field.

placeholder
''
string

The placeholder character to use for empty pin-inputs.

required
boolean

When true, indicates that the user must check the pin input before the owning form can be submitted.

type
'text'
'number' | 'text'

Input type for the inputs.

EmitPayload
complete
[value: string[]]
update:modelValue
[value: string[]]

Event handler called when the value changes.

Slots (default)Payload
modelValue
string[]

Current input values

Data AttributeValue
[data-complete]Present when completed
[data-disabled]Present when disabled

Input

Input field for Pin Input. You can add as many input as you like.

PropDefaultType
as
'input'
AsTag | Component

The element or component this component should render as. Can be overwrite by asChild

asChild
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

disabled
boolean

When true, prevents the user from interacting with the pin input

index*
number

Position of the value this input binds to.

Data AttributeValue
[data-complete]Present when completed
[data-disabled]Present when disabled

Examples

OTP mode

You can set the pin input to otp mode by setting otp to true.

vue
<script setup lang="ts"> 
import { Label, PinInputInput, PinInputRoot } from 'radix-vue' 
</script>

<template>
  <PinInputRoot v-model="value" otp>

  </PinInputRoot>
</template>

Numeric mode

You can set the pin input to only accept number type by setting type to number.

vue
<script setup lang="ts"> 
import { Label, PinInputInput, PinInputRoot } from 'radix-vue' 
</script>

<template>
  <PinInputRoot v-model="value" type="number">

  </PinInputRoot>
</template>

Accessibility

Keyboard Interactions

KeyDescription
ArrowLeft
Focus on previous input.
ArrowRight
Focus on next input.
Home
Focus on the first input.
End
Focus on the last input.
Backspace
Deletes the value of the current input. If the input is empty, moves to the previous input and deletes that value as well.
Delete
Deletes the value of the current input.
Ctrl + V
Pastes the contents of the clipboard into the pin input. If the number of characters in the clipboard equals exceeds the number of inputs, the contents are pasted from the first input. Otherwise, the contents are pasted from the current input onwards.