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>
)
}
Count
To increase the number of input fields, you can use the count
prop.
import { PinInput } from "@/components/ui/pin-input"
const Demo = () => {
return <PinInput count={6} />
}
Props
Root
Prop | Default | Type |
---|---|---|
placeholder | '\'â—‹\'' | string The 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 | boolean 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. | |
id | string The 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 | 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. | |
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 | |
value | string[] The value of the the pin input. |