import { PinInput } from "@/components/ui/pin-input"
const Demo = () => {
return <PinInput />
}
Setup
If you don't already have the snippet, run the following command to add the
pin-input snippet
npx @chakra-ui/cli snippet add pin-input
The snippet includes a closed component composition for the PinInput
component.
Usage
import { PinInput } from "@/components/ui/pin-input"
<PinInput />
Examples
Sizes
Use the size prop to change the size of the pin input component.
import { Stack } from "@chakra-ui/react"
import { PinInput } from "@/components/ui/pin-input"
const Demo = () => {
return (
<Stack gap="4">
<PinInput size="sm" />
<PinInput size="md" />
<PinInput size="lg" />
</Stack>
)
}
One time code
Use the otp prop 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 "@/components/ui/pin-input"
const Demo = () => {
return <PinInput otp />
}
Mask
Use the mask prop to obscure the entered pin code.
import { PinInput } from "@/components/ui/pin-input"
const Demo = () => {
return <PinInput mask />
}
Placeholder
Use the placeholder prop to add a placeholder to the pin input component.
import { PinInput } from "@/components/ui/pin-input"
const Demo = () => {
return <PinInput placeholder="🥳" />
}
Field
Here's an example of how to compose the Field and the PinInput components
import { Field } from "@/components/ui/field"
import { PinInput } from "@/components/ui/pin-input"
const Demo = () => {
return (
<Field label="Enter otp">
<PinInput />
</Field>
)
}
Hook Form
Here's an example of how to compose the Field and the PinInput components
with react-hook-form
"use client"
import { Button, Stack } from "@chakra-ui/react"
import { zodResolver } from "@hookform/resolvers/zod"
import { Field } from "@/components/ui/field"
import { PinInput } from "@/components/ui/pin-input"
import { Controller, useForm } from "react-hook-form"
import { z } from "zod"
const formSchema = z.object({
pin: z
.array(z.string().min(1), { required_error: "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: zodResolver(formSchema),
})
const onSubmit = handleSubmit((data) => console.log(data))
return (
<form onSubmit={onSubmit}>
<Stack gap="4" align="flex-start" maxW="sm">
<Field
invalid={!!formState.errors.pin}
errorText={formState.errors.pin?.message}
>
<Controller
control={control}
name="pin"
render={({ field }) => (
<PinInput
value={field.value}
onValueChange={(e) => field.onChange(e.value)}
/>
)}
/>
</Field>
<Button type="submit">Submit</Button>
</Stack>
</form>
)
}
Controlled
Use the value and onValueChange props to control the value of the pin input
"use client"
import { PinInput } from "@/components/ui/pin-input"
import { useState } from "react"
const Demo = () => {
const [value, setValue] = useState(["", "", "", ""])
return <PinInput value={value} onValueChange={(e) => setValue(e.value)} />
}
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 display="flex" gap="2">
{Array.from({ length: 4 }).map((_, index) => (
<PinInput.Input key={index} index={index} />
))}
</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
Use the attached prop to attach the pin input to the input field
import { PinInput } from "@/components/ui/pin-input"
const Demo = () => {
return <PinInput attached />
}
Alphanumeric
Use the type prop to allow the user to enter alphanumeric characters. Values
can be either alphanumeric, numeric, or alphabetic
import { PinInput } from "@/components/ui/pin-input"
const Demo = () => {
return <PinInput type="alphanumeric" />
}
Without Snippet
If you don't want to use the snippet, you can use the PinInput component from
the @chakra-ui/react package.
import { PinInput } from "@chakra-ui/react"
const Demo = () => {
return (
<PinInput.Root>
<PinInput.Label>Enter your OTP</PinInput.Label>
<PinInput.HiddenInput />
<PinInput.Control>
{Array.from({ length: 4 }).map((_, index) => (
<PinInput.Input key={index} index={index} />
))}
</PinInput.Control>
</PinInput.Root>
)
}
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' | 'accent'The color palette of the component |
size | 'md' | 'lg' | 'md' | 'sm' | 'xs'The size of the component |
variant | 'outline' | 'outline' | 'filled' | 'flushed'The variant of the component |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
autoFocus | booleanWhether to auto-focus the first input. | |
blurOnComplete | booleanWhether 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 | 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 value of the the pin input. |