Components
Pin input

Pin Input

For pin or verification codes with auto-focus transfer and masking options.

Anatomy

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-part attribute to help identify them in the DOM.

Examples

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/solid/pin-input'
import { Index } from 'solid-js'

export 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.HiddenInput />
  </PinInput.Root>
)

Setting a default value

To set the initial value of the pin input, set the defaultValue prop.

import { PinInput } from '@ark-ui/solid/pin-input'
import { Index } from 'solid-js'

export 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.HiddenInput />
  </PinInput.Root>
)

Changing the placeholder

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/solid/pin-input'
import { Index } from 'solid-js'

export 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.HiddenInput />
  </PinInput.Root>
)

Blur on complete

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/solid/pin-input'
import { Index } from 'solid-js'

export 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.HiddenInput />
  </PinInput.Root>
)

Using OTP mode

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/solid/pin-input'
import { Index } from 'solid-js'

export 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.HiddenInput />
  </PinInput.Root>
)

Securing the text input

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/solid/pin-input'
import { Index } from 'solid-js'

export 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.HiddenInput />
  </PinInput.Root>
)

Listening for changes

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

Using the Field Component

The Field component helps manage form-related state and accessibility attributes of a pin input. It includes handling ARIA labels, helper text, and error text to ensure proper accessibility.

import { Field } from '@ark-ui/solid/field'
import { PinInput } from '@ark-ui/solid/pin-input'
import { Index } from 'solid-js'

export const WithField = (props: Field.RootProps) => (
  <Field.Root {...props}>
    <PinInput.Root>
      <PinInput.Label>Label</PinInput.Label>
      <PinInput.Control>
        <Index each={[0, 1, 2]}>{(id) => <PinInput.Input index={id()} />}</Index>
      </PinInput.Control>
      <PinInput.HiddenInput />
    </PinInput.Root>
    <Field.HelperText>Additional Info</Field.HelperText>
    <Field.ErrorText>Error Info</Field.ErrorText>
  </Field.Root>
)

Using the Root Provider

The RootProvider component provides a context for the pin-input. It accepts the value of the usePin-input hook. You can leverage it to access the component state and methods from outside the pin-input.

import { PinInput, usePinInput } from '@ark-ui/solid/pin-input'
import { Index } from 'solid-js'

export const RootProvider = () => {
  const pinInput = usePinInput({ onValueComplete: (e) => alert(e.valueAsString) })

  return (
    <>
      <button onClick={() => pinInput().focus()}>Focus</button>

      <PinInput.RootProvider value={pinInput}>
        <PinInput.Label>Label</PinInput.Label>
        <PinInput.Control>
          <Index each={[0, 1, 2]}>{(id) => <PinInput.Input index={id()} />}</Index>
        </PinInput.Control>
        <PinInput.HiddenInput />
      </PinInput.RootProvider>
    </>
  )
}

If you're using the RootProvider component, you don't need to use the Root component.

API Reference

Root

PropDefaultType
asChild
(props: ParentProps<'div'>) => Element

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
autoFocus
boolean

Whether to auto-focus the first input.

blurOnComplete
boolean

Whether to blur the input when the value is complete

defaultValue
string[]

The initial value of the pin input when it is first rendered. Use when you do not need to control the state of the pin input

disabled
boolean

Whether the inputs are disabled

form
string

The associate form of the underlying input element.

ids
Partial<{ root: string hiddenInput: string label: string control: string input(id: string): string }>

The ids of the elements in the pin input. Useful for composition.

invalid
boolean

Whether the pin input is in the invalid state

mask
boolean

If `true`, the input's value will be masked just like `type=password`

name
string

The name of the input element. Useful for form submission.

onValueChange
(details: ValueChangeDetails) => void

Function called on input change

onValueComplete
(details: ValueChangeDetails) => void

Function called when all inputs have valid values

onValueInvalid
(details: ValueInvalidDetails) => void

Function called when an invalid value is entered

otp
boolean

If `true`, the pin input component signals to its fields that they should use `autocomplete="one-time-code"`.

pattern
string

The regular expression that the user-entered input value is checked against.

placeholder'○'
string

The placeholder text for the input

readOnly
boolean

Whether the pin input is in the valid state

required
boolean

Whether the pin input is required

selectOnFocus
boolean

Whether to select input value when input is focused

translations
IntlTranslations

Specifies the localized strings that identifies the accessibility elements and their states

type'numeric'
'numeric' | 'alphabetic' | 'alphanumeric'

The type of value the pin-input should allow

value
string[]

The value of the the pin input.

Data AttributeValue
[data-scope]pin-input
[data-part]root
[data-invalid]Present when invalid
[data-disabled]Present when disabled
[data-complete]Present when the pin-input value is complete
[data-readonly]Present when read-only

Control

PropDefaultType
asChild
(props: ParentProps<'div'>) => Element

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

HiddenInput

PropDefaultType
asChild
(props: ParentProps<'input'>) => Element

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

Input

PropDefaultType
index
number

asChild
(props: ParentProps<'input'>) => Element

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
Data AttributeValue
[data-scope]pin-input
[data-part]input
[data-disabled]Present when disabled
[data-complete]Present when the input value is complete
[data-invalid]Present when invalid

Label

PropDefaultType
asChild
(props: ParentProps<'label'>) => Element

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
Data AttributeValue
[data-scope]pin-input
[data-part]label
[data-invalid]Present when invalid
[data-disabled]Present when disabled
[data-complete]Present when the label value is complete
[data-readonly]Present when read-only

RootProvider

PropDefaultType
value
UsePinInputReturn

asChild
(props: ParentProps<'div'>) => Element

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

Accessibility

Keyboard Support

KeyDescription
ArrowLeft
Moves focus to the previous input
ArrowRight
Moves focus to the next input
Backspace
Deletes the value in the current input and moves focus to the previous input
Delete
Deletes the value in the current input
Control + V
Pastes the value into the input fields