Pin Input
Used to capture a pin code or otp from the user
import { PinInput } from "@chakra-ui/react"
const Demo = () => {
return (
<PinInput.Root>
<PinInput.HiddenInput />
<PinInput.Control>
<PinInput.Input index={0} />
<PinInput.Input index={1} />
<PinInput.Input index={2} />
<PinInput.Input index={3} />
</PinInput.Control>
</PinInput.Root>
)
}
Usage
import { PinInput } from "@chakra-ui/react"<PinInput.Root>
<PinInput.HiddenInput />
<PinInput.Control>
<PinInput.Input />
</PinInput.Control>
</PinInput.Root>Examples
Sizes
Pass the size prop to the PinInput.Root component to change the size of the
pin input component
import { For, PinInput, Stack } from "@chakra-ui/react"
const Demo = () => {
return (
<Stack gap="4">
<For each={["sm", "md", "lg"]}>
{(size) => (
<PinInput.Root key={size} size={size}>
<PinInput.HiddenInput />
<PinInput.Control>
<PinInput.Input index={0} />
<PinInput.Input index={1} />
<PinInput.Input index={2} />
<PinInput.Input index={3} />
</PinInput.Control>
</PinInput.Root>
)}
</For>
</Stack>
)
}
One time code
Pass the otp prop to the PinInput.Root component to make the pin input
component behave like a one-time code input. This helps improve the user
experience when entering OTP codes
import { PinInput } from "@chakra-ui/react"
const Demo = () => {
return (
<PinInput.Root otp>
<PinInput.HiddenInput />
<PinInput.Control>
<PinInput.Input index={0} />
<PinInput.Input index={1} />
<PinInput.Input index={2} />
<PinInput.Input index={3} />
</PinInput.Control>
</PinInput.Root>
)
}
Mask
Pass the mask prop to the PinInput.Root component to obscure the entered pin
code
import { PinInput } from "@chakra-ui/react"
const Demo = () => {
return (
<PinInput.Root mask>
<PinInput.HiddenInput />
<PinInput.Control>
<PinInput.Input index={0} />
<PinInput.Input index={1} />
<PinInput.Input index={2} />
<PinInput.Input index={3} />
</PinInput.Control>
</PinInput.Root>
)
}
Placeholder
Pass the placeholder prop to the PinInPut.Root component to add a
placeholder to the pin input
import { PinInput } from "@chakra-ui/react"
const Demo = () => {
return (
<PinInput.Root placeholder="🥳">
<PinInput.HiddenInput />
<PinInput.Control>
<PinInput.Input index={0} />
<PinInput.Input index={1} />
<PinInput.Input index={2} />
<PinInput.Input index={3} />
</PinInput.Control>
</PinInput.Root>
)
}
Field
Here's an example of how to compose the Field and the PinInput components
import { Field, PinInput } from "@chakra-ui/react"
const Demo = () => {
return (
<Field.Root>
<Field.Label>Enter otp</Field.Label>
<PinInput.Root>
<PinInput.HiddenInput />
<PinInput.Control>
<PinInput.Input index={0} />
<PinInput.Input index={1} />
<PinInput.Input index={2} />
<PinInput.Input index={3} />
</PinInput.Control>
</PinInput.Root>
</Field.Root>
)
}
Hook Form
Here's an example of how to compose the Field and the PinInput components
with react-hook-form
"use client"
import { Button, Field, PinInput, Stack } from "@chakra-ui/react"
import { standardSchemaResolver } from "@hookform/resolvers/standard-schema"
import { Controller, useForm } from "react-hook-form"
import { z } from "zod"
const formSchema = z.object({
pin: z
.array(z.string().min(1))
.min(1, { message: "Pin is required" })
.length(4, { message: "Pin must be 4 digits long" }),
})
type FormValues = z.infer<typeof formSchema>
const Demo = () => {
const { handleSubmit, control, formState } = useForm<FormValues>({
resolver: standardSchemaResolver(formSchema),
})
const onSubmit = handleSubmit((data) => console.log(data))
return (
<form onSubmit={onSubmit}>
<Stack gap="4" align="flex-start" maxW="sm">
<Field.Root invalid={!!formState.errors.pin}>
<Controller
control={control}
name="pin"
render={({ field }) => (
<PinInput.Root
value={field.value}
onValueChange={(e) => field.onChange(e.value)}
>
<PinInput.HiddenInput />
<PinInput.Control>
<PinInput.Input index={0} />
<PinInput.Input index={1} />
<PinInput.Input index={2} />
<PinInput.Input index={3} />
</PinInput.Control>
</PinInput.Root>
)}
/>
<Field.ErrorText>{formState.errors.pin?.message}</Field.ErrorText>
</Field.Root>
<Button type="submit">Submit</Button>
</Stack>
</form>
)
}
Controlled
Pass the value and onValueChange props to the PinInPut.Root component to
control the value of the pin input
"use client"
import { PinInput } from "@chakra-ui/react"
import { useState } from "react"
const Demo = () => {
const [value, setValue] = useState(["", "", "", ""])
return (
<PinInput.Root value={value} onValueChange={(e) => setValue(e.value)}>
<PinInput.HiddenInput />
<PinInput.Control>
<PinInput.Input index={0} />
<PinInput.Input index={1} />
<PinInput.Input index={2} />
<PinInput.Input index={3} />
</PinInput.Control>
</PinInput.Root>
)
}
Store
An alternative way to control the pin input is to use the RootProvider
component and the usePinInput store hook.
This way you can access the pin input state and methods from outside the component.
"use client"
import {
Button,
ButtonGroup,
PinInput,
Stack,
usePinInput,
} from "@chakra-ui/react"
const Demo = () => {
const store = usePinInput()
return (
<Stack align="flex-start">
<PinInput.RootProvider value={store}>
<PinInput.Control>
<PinInput.Input index={0} />
<PinInput.Input index={1} />
<PinInput.Input index={2} />
<PinInput.Input index={3} />
</PinInput.Control>
</PinInput.RootProvider>
<ButtonGroup variant="outline" size="sm">
<Button onClick={() => store.setValue(["1", "2", "3", "4"])}>
Set value
</Button>
<Button onClick={() => store.clearValue()}>Clear value</Button>
</ButtonGroup>
</Stack>
)
}
Attached
Pass the attached prop to the PinInput.Root component to attach the pin
input to the input field
import { PinInput } from "@chakra-ui/react"
const Demo = () => {
return (
<PinInput.Root attached>
<PinInput.HiddenInput />
<PinInput.Control>
<PinInput.Input index={0} />
<PinInput.Input index={1} />
<PinInput.Input index={2} />
<PinInput.Input index={3} />
</PinInput.Control>
</PinInput.Root>
)
}
Alphanumeric
Pass the type prop to the PinInput.Root component to allow the user to enter
alphanumeric characters. Values can be either alphanumeric, numeric, or
alphabetic
import { PinInput } from "@chakra-ui/react"
const Demo = () => {
return (
<PinInput.Root type="alphanumeric">
<PinInput.HiddenInput />
<PinInput.Control>
<PinInput.Input index={0} />
<PinInput.Input index={1} />
<PinInput.Input index={2} />
<PinInput.Input index={3} />
</PinInput.Control>
</PinInput.Root>
)
}
Closed Component
Here's how to setup the Pin input for a closed component composition.
import { PinInput as ChakraPinInput, Group } from "@chakra-ui/react"
import * as React from "react"
export interface PinInputProps extends ChakraPinInput.RootProps {
rootRef?: React.RefObject<HTMLDivElement | null>
count?: number
inputProps?: React.InputHTMLAttributes<HTMLInputElement>
attached?: boolean
}
export const PinInput = React.forwardRef<HTMLInputElement, PinInputProps>(
function PinInput(props, ref) {
const { count = 4, inputProps, rootRef, attached, ...rest } = props
return (
<ChakraPinInput.Root ref={rootRef} {...rest}>
<ChakraPinInput.HiddenInput ref={ref} {...inputProps} />
<ChakraPinInput.Control>
<Group attached={attached}>
{Array.from({ length: count }).map((_, index) => (
<ChakraPinInput.Input key={index} index={index} />
))}
</Group>
</ChakraPinInput.Control>
</ChakraPinInput.Root>
)
},
)
Usage
<PinInput mask />Props
Root
| Prop | Default | Type |
|---|---|---|
placeholder | '\'â—‹\'' | stringThe placeholder text for the input |
type | '\'numeric\'' | 'numeric' | 'alphabetic' | 'alphanumeric'The type of value the pin-input should allow |
colorPalette | 'gray' | 'gray' | 'red' | 'orange' | 'yellow' | 'green' | 'teal' | 'blue' | 'cyan' | 'purple' | 'pink'The color palette of the component |
size | 'md' | '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'The size of the component |
variant | 'outline' | 'outline' | 'subtle' | 'flushed'The variant of the component |
as | React.ElementTypeThe underlying element to render. | |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
unstyled | booleanWhether to remove the component's style. | |
autoFocus | booleanWhether to auto-focus the first input. | |
blurOnComplete | booleanWhether to blur the input when the value is complete | |
count | numberThe number of inputs to render to improve SSR aria attributes. This will be required in next major version. | |
defaultValue | string[]The initial value of the the pin input when rendered. Use when you don't need to control the value of the pin input. | |
disabled | booleanWhether the inputs are disabled | |
form | stringThe associate form of the underlying input element. | |
id | stringThe unique identifier of the machine. | |
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 | booleanWhether the pin input is in the invalid state | |
mask | booleanIf `true`, the input's value will be masked just like `type=password` | |
name | stringThe name of the input element. Useful for form submission. | |
onValueChange | (details: ValueChangeDetails) => voidFunction called on input change | |
onValueComplete | (details: ValueChangeDetails) => voidFunction called when all inputs have valid values | |
onValueInvalid | (details: ValueInvalidDetails) => voidFunction called when an invalid value is entered | |
otp | booleanIf `true`, the pin input component signals to its fields that they should use `autocomplete="one-time-code"`. | |
pattern | stringThe regular expression that the user-entered input value is checked against. | |
readOnly | booleanWhether the pin input is in the valid state | |
required | booleanWhether the pin input is required | |
selectOnFocus | booleanWhether to select input value when input is focused | |
translations | IntlTranslationsSpecifies the localized strings that identifies the accessibility elements and their states | |
value | string[]The controlled value of the the pin input. | |
attached | 'true' | 'false'The attached of the component |
Explorer
Explore the Pin Input component parts interactively. Click on parts in the
sidebar to highlight them in the preview.
Component Anatomy
Hover to highlight, click to select parts
root
label
input
control
pin-input.recipe.ts