Components
Loading preview...
A customizable number pad component for entering numeric values, supporting various formats like currency, phone, decimal, integer, percentage, pin, and time. Features both button-based and keyboard input with type-specific validation and formatting.
npx shadcn@latest add https://21st.dev/r/bankkroll/number-padimport { NumberPad, formatters } from "@/components/ui/number-pad";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { DollarSign, Phone, Percent, Lock, Clock, Calculator, CreditCard, Globe } from "lucide-react";
import { useState } from "react";
const CurrencyDemo = () => {
const [value, setValue] = useState('');
return (
<Card className="w-full max-w-md mx-auto">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<DollarSign className="h-5 w-5" />
US Currency Input
</CardTitle>
<CardDescription>
USD currency with American formatting and validation
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="text-center">
<Badge variant="outline" className="text-lg px-4 py-2">
{value ? formatters.currency(value, 'USD', 'en-US') : ''}
</Badge>
</div>
<NumberPad
title="Enter USD Amount"
type="currency"
currency="USD"
locale="en-US"
onValueChange={setValue}
maxLength={12}
/>
</CardContent>
</Card>
);
};
const EuroCurrencyDemo = () => {
const [value, setValue] = useState('');
return (
<Card className="w-full max-w-md mx-auto">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Globe className="h-5 w-5" />
Euro Currency Input
</CardTitle>
<CardDescription>
EUR currency with European formatting (comma as decimal separator)
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="text-center">
<Badge variant="outline" className="text-lg px-4 py-2">
{value ? formatters.currency(value, 'EUR', 'de-DE') : ''}
</Badge>
</div>
<NumberPad
title="Enter EUR Amount"
type="currency"
currency="EUR"
locale="de-DE"
onValueChange={setValue}
maxLength={12}
/>
</CardContent>
</Card>
);
};
const PhoneDemo = () => {
const [value, setValue] = useState('');
return (
<Card className="w-full max-w-md mx-auto">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Phone className="h-5 w-5" />
Phone Number Input
</CardTitle>
<CardDescription>
US phone number with automatic formatting
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="text-center">
<Badge variant="outline" className="text-lg px-4 py-2">
{value ? formatters.phone(value, 'US') : ''}
</Badge>
</div>
<NumberPad
title="Enter Phone Number"
type="phone"
countryCode="US"
onValueChange={setValue}
maxLength={10}
/>
</CardContent>
</Card>
);
};
const PercentageDemo = () => {
const [value, setValue] = useState('');
return (
<Card className="w-full max-w-md mx-auto">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Percent className="h-5 w-5" />
Percentage Input
</CardTitle>
<CardDescription>
Percentage input with decimal support and validation
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="text-center">
<Badge variant="outline" className="text-lg px-4 py-2">
{value ? formatters.percentage(value) : ''}
</Badge>
</div>
<NumberPad
title="Enter Percentage"
type="percentage"
onValueChange={setValue}
maxLength={6}
/>
</CardContent>
</Card>
);
};
const PinDemo = () => {
const [value, setValue] = useState('');
return (
<Card className="w-full max-w-md mx-auto">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Lock className="h-5 w-5" />
Secure PIN Input
</CardTitle>
<CardDescription>
PIN input with masking for security
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="text-center">
<Badge variant="outline" className="text-lg px-4 py-2">
{value ? formatters.pin(value, true) : ''}
</Badge>
</div>
<NumberPad
title="Enter PIN"
type="pin"
maskInput={true}
onValueChange={setValue}
maxLength={6}
/>
</CardContent>
</Card>
);
};
const TimeDemo = () => {
const [value, setValue] = useState('');
return (
<Card className="w-full max-w-md mx-auto">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Clock className="h-5 w-5" />
Time Input
</CardTitle>
<CardDescription>
24-hour time format with HH:MM structure
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="text-center">
<Badge variant="outline" className="text-lg px-4 py-2">
{value ? formatters.time(value) : ''}
</Badge>
</div>
<NumberPad
title="Enter Time"
type="time"
onValueChange={setValue}
maxLength={4}
/>
</CardContent>
</Card>
);
};
const DecimalDemo = () => {
const [value, setValue] = useState('');
return (
<Card className="w-full max-w-md mx-auto">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Calculator className="h-5 w-5" />
Decimal Number Input
</CardTitle>
<CardDescription>
Standard decimal number input with locale formatting
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="text-center">
<Badge variant="outline" className="text-lg px-4 py-2">
{value ? formatters.decimal(value, 'en-US') : ''}
</Badge>
</div>
<NumberPad
title="Enter Decimal"
type="decimal"
onValueChange={setValue}
maxLength={10}
/>
</CardContent>
</Card>
);
};
const IntegerDemo = () => {
const [value, setValue] = useState('');
return (
<Card className="w-full max-w-md mx-auto">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<CreditCard className="h-5 w-5" />
Integer Input
</CardTitle>
<CardDescription>
Whole numbers only - no decimal points allowed
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="text-center">
<Badge variant="outline" className="text-lg px-4 py-2">
{value || ''}
</Badge>
</div>
<NumberPad
title="Enter Integer"
type="integer"
onValueChange={setValue}
maxLength={8}
/>
</CardContent>
</Card>
);
};
export {
CurrencyDemo,
EuroCurrencyDemo,
PhoneDemo,
PercentageDemo,
PinDemo,
TimeDemo,
DecimalDemo,
IntegerDemo
};