Pin Input
For pin or verification codes with auto-focus transfer and masking options.
For pin or verification codes with auto-focus transfer and masking options.
To set up the pin input correctly, you’ll need to understand its anatomy and how we name its parts.
Each part includes a
data-partattribute to help identify them in the DOM.
Learn how to use the PinInput component in your project. Let’s take a look at
the most basic example:
import { PinInput } from '@ark-ui/react'
const Basic = () => (
  <PinInput.Root onValueComplete={(e) => alert(e.valueAsString)}>
    <PinInput.Label>Label</PinInput.Label>
    <PinInput.Control>
      {[0, 1, 2].map((id, index) => (
        <PinInput.Input key={id} index={index} />
      ))}
    </PinInput.Control>
  </PinInput.Root>
)
import { PinInput } from '@ark-ui/solid'
import { Index } from 'solid-js'
const Basic = () => (
  <PinInput.Root onValueComplete={(e) => alert(e.valueAsString)}>
    <PinInput.Label>Label</PinInput.Label>
    <PinInput.Control>
      <Index each={[0, 1, 2]}>{(id) => <PinInput.Input index={id()} />}</Index>
    </PinInput.Control>
  </PinInput.Root>
)
<script setup lang="ts">
import { PinInput } from '@ark-ui/vue'
</script>
<template>
  <PinInput.Root @value-complete="(e) => console.log(e.valueAsString)">
    <PinInput.Label>Label</PinInput.Label>
    <PinInput.Control>
      <PinInput.Input v-for="id in [0, 1, 2]" :key="id" :index="id" />
    </PinInput.Control>
  </PinInput.Root>
</template>
To set the initial value of the pin input, set the defaultValue prop.
import { PinInput } from '@ark-ui/react'
const InitialValue = () => (
  <PinInput.Root defaultValue={['1', '2', '3']}>
    <PinInput.Label>Label</PinInput.Label>
    <PinInput.Control>
      {[0, 1, 2].map((id, index) => (
        <PinInput.Input key={id} index={index} />
      ))}
    </PinInput.Control>
  </PinInput.Root>
)
import { PinInput } from '@ark-ui/solid'
import { Index } from 'solid-js'
const InitialValue = () => (
  <PinInput.Root value={['1', '2', '3']}>
    <PinInput.Label>Label</PinInput.Label>
    <PinInput.Control>
      <Index each={[0, 1, 2]}>{(id) => <PinInput.Input index={id()} />}</Index>
    </PinInput.Control>
  </PinInput.Root>
)
<script setup lang="ts">
import { PinInput } from '@ark-ui/vue'
</script>
<template>
  <PinInput.Root :model-value="['1', '2', '3']">
    <PinInput.Label>Label</PinInput.Label>
    <PinInput.Control>
      <PinInput.Input v-for="id in [0, 1, 2]" :key="id" :index="id" />
    </PinInput.Control>
  </PinInput.Root>
</template>
To customize the default pin input placeholder ○ for each input, pass the
placeholder prop and set it to your desired value.
import { PinInput } from '@ark-ui/react'
const Customized = () => (
  <PinInput.Root placeholder="*">
    <PinInput.Label>Label</PinInput.Label>
    <PinInput.Control>
      {[0, 1, 2].map((id, index) => (
        <PinInput.Input key={id} index={index} />
      ))}
    </PinInput.Control>
  </PinInput.Root>
)
import { PinInput } from '@ark-ui/solid'
import { Index } from 'solid-js'
const Customized = () => (
  <PinInput.Root placeholder="*">
    <PinInput.Label>Label</PinInput.Label>
    <PinInput.Control>
      <Index each={[0, 1, 2]}>{(id) => <PinInput.Input index={id()} />}</Index>
    </PinInput.Control>
  </PinInput.Root>
)
<script setup lang="ts">
import { PinInput } from '@ark-ui/vue'
</script>
<template>
  <PinInput.Root placeholder="*">
    <PinInput.Label>Label</PinInput.Label>
    <PinInput.Control>
      <PinInput.Input v-for="id in [0, 1, 2]" :key="id" :index="id" />
    </PinInput.Control>
  </PinInput.Root>
</template>
By default, the last input maintains focus when filled, and we invoke the
onValueComplete callback. To blur the last input when the user completes the
input, set the prop blurOnComplete to true.
import { PinInput } from '@ark-ui/react'
const Blurred = () => (
  <PinInput.Root blurOnComplete>
    <PinInput.Label>Label</PinInput.Label>
    <PinInput.Control>
      {[0, 1, 2].map((id, index) => (
        <PinInput.Input key={id} index={index} />
      ))}
    </PinInput.Control>
  </PinInput.Root>
)
import { PinInput } from '@ark-ui/solid'
import { Index } from 'solid-js'
const Blurred = () => (
  <PinInput.Root blurOnComplete>
    <PinInput.Label>Label</PinInput.Label>
    <PinInput.Control>
      <Index each={[0, 1, 2]}>{(id) => <PinInput.Input index={id()} />}</Index>
    </PinInput.Control>
  </PinInput.Root>
)
<script setup lang="ts">
import { PinInput } from '@ark-ui/vue'
</script>
<template>
  <PinInput.Root blurOnComplete>
    <PinInput.Label>Label</PinInput.Label>
    <PinInput.Control>
      <PinInput.Input v-for="id in [0, 1, 2]" :key="id" :index="id" />
    </PinInput.Control>
  </PinInput.Root>
</template>
To trigger smartphone OTP auto-suggestion, it is recommended to set the
autocomplete attribute to “one-time-code”. The pin input component provides
support for this automatically when you set the otp prop to true.
import { PinInput } from '@ark-ui/react'
const OTPMode = () => (
  <PinInput.Root otp>
    <PinInput.Label>Label</PinInput.Label>
    <PinInput.Control>
      {[0, 1, 2].map((id, index) => (
        <PinInput.Input key={id} index={index} />
      ))}
    </PinInput.Control>
  </PinInput.Root>
)
import { PinInput } from '@ark-ui/solid'
import { Index } from 'solid-js'
const OTPMode = () => (
  <PinInput.Root otp>
    <PinInput.Label>Label</PinInput.Label>
    <PinInput.Control>
      <Index each={[0, 1, 2]}>{(id) => <PinInput.Input index={id()} />}</Index>
    </PinInput.Control>
  </PinInput.Root>
)
<script setup lang="ts">
import { PinInput } from '@ark-ui/vue'
</script>
<template>
  <PinInput.Root otp>
    <PinInput.Label>Label</PinInput.Label>
    <PinInput.Control>
      <PinInput.Input v-for="id in [0, 1, 2]" :key="id" :index="id" />
    </PinInput.Control>
  </PinInput.Root>
</template>
When collecting private or sensitive information using the pin input, you might
need to mask the value entered, similar to <input type="password"/>. Pass the
mask prop to true.
import { PinInput } from '@ark-ui/react'
const WithMask = () => (
  <PinInput.Root mask>
    <PinInput.Label>Label</PinInput.Label>
    <PinInput.Control>
      {[0, 1, 2].map((id, index) => (
        <PinInput.Input key={id} index={index} />
      ))}
    </PinInput.Control>
  </PinInput.Root>
)
import { PinInput } from '@ark-ui/solid'
import { Index } from 'solid-js'
const WithMask = () => (
  <PinInput.Root mask>
    <PinInput.Label>Label</PinInput.Label>
    <PinInput.Control>
      <Index each={[0, 1, 2]}>{(id) => <PinInput.Input index={id()} />}</Index>
    </PinInput.Control>
  </PinInput.Root>
)
<script setup lang="ts">
import { PinInput } from '@ark-ui/vue'
</script>
<template>
  <PinInput.Root mask>
    <PinInput.Label>Label</PinInput.Label>
    <PinInput.Control>
      <PinInput.Input v-for="id in [0, 1, 2]" :key="id" :index="id" />
    </PinInput.Control>
  </PinInput.Root>
</template>
The pin input component invokes several callback functions when the user enters:
onValueChange — Callback invoked when the value is changed.onValueComplete — Callback invoked when all fields have been completed (by
typing or pasting).onValueInvalid — Callback invoked when an invalid value is entered into the
input. An invalid value is any value that doesn’t match the specified “type”.| Prop | Type | Default | 
|---|---|---|
| asChildRender as a different element type. | boolean | |
| autoFocusWhether to auto-focus the first input. | boolean | |
| blurOnCompleteWhether to blur the input when the value is complete | boolean | |
| defaultValueThe initial value of the pin input. | string[] | |
| dirThe document's text/writing direction. | 'ltr' | 'rtl' | "ltr" | 
| disabledWhether the inputs are disabled | boolean | |
| formThe associate form of the underlying input element. | string | |
| getRootNodeA root node to correctly resolve document in custom environments. E.x.: Iframes, Electron. | () => Node | ShadowRoot | Document | |
| idThe unique identifier of the machine. | string | |
| idsThe ids of the elements in the pin input. Useful for composition. | Partial<{
  root: string
  hiddenInput: string
  label: string
  control: string
  input(id: string): string
}> | |
| invalidWhether the pin input is in the invalid state | boolean | |
| maskIf `true`, the input's value will be masked just like `type=password` | boolean | |
| nameThe name of the input element. Useful for form submission. | string | |
| onValueChangeFunction called on input change | (details: ValueChangeDetails) => void | |
| onValueCompleteFunction called when all inputs have valid values | (details: ValueChangeDetails) => void | |
| onValueInvalidFunction called when an invalid value is entered | (details: ValueInvalidDetails) => void | |
| otpIf `true`, the pin input component signals to its fields that they should use `autocomplete="one-time-code"`. | boolean | |
| patternThe regular expression that the user-entered input value is checked against. | string | |
| placeholderThe placeholder text for the input | string | |
| selectOnFocusWhether to select input value when input is focused | boolean | |
| translationsSpecifies the localized strings that identifies the accessibility elements and their states | IntlTranslations | |
| typeThe type of value the pin-input should allow | 'alphabetic' | 'numeric' | 'alphanumeric' | |
| valueThe value of the the pin input. | string[] | 
| Prop | Type | Default | 
|---|---|---|
| index | number | |
| asChildRender as a different element type. | boolean | 
| Prop | Type | Default | 
|---|---|---|
| asChildRender as a different element type. | boolean | 
| Prop | Type | Default | 
|---|---|---|
| asChildRender as a different element type. | boolean | 
Previous
PaginationNext
Popover