suiss/uim · React Native Component

Pin Pad

A passcode entry screen element with a row of dots and a numeric keypad.

Pin Pad is an open-source mobile component from suiss/uim for React Native and Expo, with SwiftUI and Jetpack Compose versions built from the same design tokens. The @esuiss/uim CLI copies its source into your project, so you own the code.

iOS
Pin Pad on iOS in light mode

PinPad combines a row of dots that fill as digits are entered with a Keypad for input. The length is between 4 and 8 digits. Each key press plays a selection haptic, and switching to the error state turns the dots red, plays an error haptic and shakes the row with Reanimated.

An optional biometric key appears in the bottom-left corner of the keypad when onBiometric is set, and the delete key is disabled while nothing is entered.

Installation

$ pnpm dlx @esuiss/uim@latest add pin-pad

The CLI also adds what it builds on: Keypad.

Manual

  1. Install the dependencies:
npx expo install cn phosphor-react-native react-native-reanimated react-native-svg react-native-worklets
  1. Add the pieces it builds on: Keypad, and the primitives components/primitives/haptics.tsx, components/primitives/hooks.tsx.

  2. Copy the source into components/ui/pin-pad.tsx:

uniwind/components/ui/pin-pad.tsx
import { cn } from "cn"
import type { Icon as PhosphorIcon } from "phosphor-react-native"
import * as React from "react"
import { View } from "react-native"
import {
  ReduceMotion,
  useAnimatedStyle,
  useSharedValue,
  withSequence,
  withTiming,
} from "react-native-reanimated"
import { useHaptics } from "@/components/primitives/haptics"
import { useEffectEvent } from "@/components/primitives/hooks"
import { AnimatedView } from "@/components/ui/animated-view"
import { Keypad, type KeypadKeyValue } from "@/components/ui/keypad"
  1. Update the import paths to match your project.

Usage

import { PinPad } from "@/components/ui/pin-pad"
<PinPad />

Use it uncontrolled with defaultValue, or controlled with value and onValueChange. onComplete fires with the full code once the last digit is entered; check the code there, set error when it is wrong and clear the value to let the user try again.

Pass onBiometric to show the biometric key, with biometricIcon and biometricLabel to match the method in use. Style the dots and keypad separately with dotsClassName and keypadClassName.

Examples

Filled

A pin pad with four of six digits entered.

iOS
Pin Pad (filled) on iOS in light mode

Error

The error state with red dots.

iOS
Pin Pad (error state) on iOS in light mode

Verify

Checks the code on completion, shows an error for a wrong code and clears it.

iOS
Pin Pad (verify) on iOS in light mode

Disabled

A disabled pin pad with a biometric key.

iOS
Pin Pad (disabled) on iOS in light mode

Biometric

A biometric key with the default fingerprint icon.

iOS
Pin Pad (biometric) on iOS in light mode

Face biometric

A biometric key with a face icon and a matching label.

iOS
Pin Pad (face biometric) on iOS in light mode

Four digits

A four-digit code with length={4}.

iOS
Pin Pad (four digits) on iOS in light mode

API Reference

PinPad

ExtendsReact.ComponentProps<typeof View>
PropType
About
Number of digits, clamped between 4 and 8. Defaults to 6.
Type
number
Default
6
About
Entered digits for controlled use.
Type
string
Default
—
About
Initial digits for uncontrolled use. Non-digits are removed.
Type
string
Default
""
About
Called with the new value after each digit or deletion.
Type
(value: string) => void
Default
—
About
Called with the full code when the last digit is entered.
Type
(value: string) => void
Default
—
About
Shows the error state. Turning it on shakes the dots and plays an error haptic.
Type
boolean
Default
false
About
Turns off the keypad and dims the dots.
Type
boolean
Default
false
About
Called when the biometric key is pressed. The key is shown only when this is set.
Type
() => void
Default
—
About
Icon for the biometric key.
Type
PhosphorIcon
Default
—
About
Accessibility label for the biometric key.
Type
string
Default
—
About
Accessibility label for the delete key.
Type
string
Default
—
About
Builds the dots label from the entered count and the length. Defaults to "3 of 6 entered".
Type
(entered: number, length: number) => string
Default
defaultDotsLabel
About
Classes for the dots row.
Type
string
Default
—
About
Classes for the keypad.
Type
string
Default
—

Accessibility

  • The dots row is a single element labeled by dotsLabel, so screen readers hear progress without the digits.
  • The row is a polite live region, so TalkBack announces progress as it changes.
  • Keypad keys are buttons labeled with their digit; the delete and biometric keys use deleteLabel and biometricLabel.
  • The shake animation respects the system reduce motion setting.

Notes

  • Uses bg-label for filled dots, border-separator-strong for empty ones and bg-danger in the error state; colors follow the system appearance.