Keypad

Pro

A touch number pad for PINs, quantities and amounts: keys sized for a finger, masked dots, a rejection shake and physical keyboard support.

Enter your PIN (2580)

0 of 4

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Activate your Pro license (once per machine)npx koalaui-cli@latest login <key># Add this component (its dependencies come along)npx koalaui-cli@latest add keypad

Usage#

This example is part of Koala UI Pro

The preview is yours to explore. Its code comes with a Pro license, paid once and used in every project.

Have a license? Unlock it here

Reach for OTPInput when a keyboard is already there and someone is typing a code into a field. Keypad is for screens with no keyboard to rely on, such as a till, a kiosk or a door panel.

Anatomy#

import {  Keypad,  KeypadClear,  KeypadConfirm,  KeypadDelete,  KeypadDigits,  KeypadDisplay,  KeypadGrid,  KeypadKey,} from "@/components/ui/keypad"<Keypad>  <KeypadDisplay />  <KeypadGrid>    <KeypadDigits />    <KeypadClear />    <KeypadKey value="0" />    <KeypadDelete />    <KeypadConfirm />  </KeypadGrid></Keypad>

Sizes#

Every size is meant for a finger. md suits a phone, lg a tablet or a till, and xl a wall panel or a kiosk used at arm's length. Leave out a part and the grid closes up: place 0 with col-start-2 when there is no clear key.

0 of 4
0 of 4
0 of 4

Digit order#

PIN pads and phones start at 1 on the top row. Tills and calculators start at 7, which is what cashiers reach for without looking. Pass order="calculator" for those, and set masked={false} to show the value.

12

Amounts#

Add decimal and a KeypadKey for the separator. The value always uses ".", so it parses with Number(), while the key and format show whatever your locale expects.

Translated labels#

Every word the pad says can be replaced, including the ones only a screen reader hears: aria-label on the root and on KeypadDelete, statusLabel on the display, and the children of KeypadClear and KeypadConfirm. Use LabelsProvider to set them once for a whole app.

0 de 4

Disabled#

Use disabled for a lockout after too many attempts. Every key stops responding, on screen and from a keyboard.

2 of 4

API reference#

Keypad

The root: holds the value and listens for a physical keyboard while focus is inside it. The value is always a string, so a leading zero in a PIN survives. Accepts className, merged last.

PropTypeDefaultDescription
valuestring-The entered value, controlled.
defaultValuestring""The entered value when uncontrolled.
onValueChange(value: string) => void-Called on every press that changes the value.
maxLengthnumber-Further presses are ignored at this length. Also sets how many dots KeypadDisplay draws.
minLengthnumber-The length that enables KeypadConfirm. Defaults to maxLength, or 1 without one.
onComplete(value: string) => void-Called when the value reaches maxLength.
onConfirm(value: string) => void-Called by KeypadConfirm and the Enter key.
decimalbooleanfalseAccepts one ".", from a KeypadKey or the . and , keys.
size"md" | "lg" | "xl""lg"Key height: 56, 64 or 80px.
disabledbooleanfalseLocks every key.
hasErrorbooleanfalseTurns the display destructive and shakes it.
errorKeystring | number-Change it to shake again while hasError stays true.
captureKeyboardbooleanfalseListens on the document, so typing works before anything is focused. Skips fields.
namestring-Adds a hidden input for forms.
Data attributeDescription
data-slot"keypad".
data-errorPresent while hasError is true.
data-disabledPresent while disabled is true.

KeypadDisplay

Shows what has been entered. Screen readers hear the status line only, never the digits of a masked value.

PropTypeDefaultDescription
maskedbooleantrueDraws dots. Set false to show the value.
placeholderReactNode-Shown while an unmasked value is empty.
format(value: string) => ReactNode-Formats an unmasked value, for example as a price.
statusLabel(length: number, maxLength?: number) => string-Replaces the English screen reader status.
Data attributeDescription
data-slot"keypad-display", with "keypad-dot" or "keypad-text" inside.

KeypadGrid

The three column grid. Scales with the root, up to the width of its size.

Data attributeDescription
data-slot"keypad-grid".

KeypadDigits

The keys 1 to 9. Renders no element of its own.

PropTypeDefaultDescription
order"phone" | "calculator""phone"1 2 3 on the top row, or 7 8 9.

KeypadKey

One key, built on Button. Children replace the label, so a decimal key can read , and still send ..

PropTypeDefaultDescription
value*string-What the key appends.
Data attributeDescription
data-slot"keypad-key".
data-valueThe value.

KeypadDelete / KeypadClear

Remove the last character, or all of them. They stay enabled while empty, so focus never falls out of the pad, and dim instead.

PropTypeDefaultDescription
aria-labelstring"Delete"KeypadDelete's accessible name.
childrenReactNode-The label. KeypadClear defaults to "Clear".
Data attributeDescription
data-slot"keypad-delete" or "keypad-clear".
data-emptyPresent while there is nothing to remove.

KeypadConfirm

The primary action, across the full width. Disabled until the value reaches minLength.

PropTypeDefaultDescription
childrenReactNode"Confirm"The label.
Data attributeDescription
data-slot"keypad-confirm".

FAQ#

Because a PIN is not a number: 0420 would lose its zero. For amounts, convert it when you read it.