Number Field
Campo numérico com botões −/+, setas do teclado e formatação automática de moeda, porcentagem e unidades.
'use client';
import { I18nProvider } from 'react-aria-components';
import { NumberField } from '@/components/ui/number-field';
export default function NumberFieldDemo() {
return (
<I18nProvider locale="pt-BR">
<NumberField label="Quantidade de páginas" defaultValue={5} minValue={1} maxValue={50} className="w-64" />
</I18nProvider>
);
}Instalação
npx shadcn@latest add @lenstech/number-fieldUso
import { I18nProvider } from "react-aria-components"
import { NumberField } from "@/components/ui/number-field"<I18nProvider locale="pt-BR">
<NumberField
label="Valor do serviço"
name="valor"
minValue={0}
formatOptions={{ style: "currency", currency: "BRL" }}
/>
</I18nProvider>O valor é sempre um number
A formatação (R$ 1.500,00, 10%, 4,5 m) é só visual: onChange recebe 1500, 0.1 ou 4.5.
O idioma define separadores — com pt-BR, vírgula decimal e ponto de milhar. Campo vazio vale NaN.
Exemplos
Moeda (BRL)
Use formatOptions={{ style: "currency", currency: "BRL" }}. O step define o incremento dos botões e das setas.
Com hideStepper o campo fica como um input simples.
'use client';
import { I18nProvider } from 'react-aria-components';
import { NumberField } from '@/components/ui/number-field';
export default function NumberFieldCurrency() {
return (
<I18nProvider locale="pt-BR">
<div className="flex w-64 flex-col gap-6">
<NumberField
label="Investimento mensal em anúncios"
defaultValue={1500}
minValue={0}
step={100}
formatOptions={{ style: 'currency', currency: 'BRL' }}
description="Valor sugerido para começar: R$ 1.500,00."
/>
<NumberField
label="Valor do serviço"
placeholder="R$ 0,00"
minValue={0}
hideStepper
formatOptions={{ style: 'currency', currency: 'BRL' }}
/>
</div>
</I18nProvider>
);
}Porcentagem
Com style: "percent" o valor é uma fração: 0.1 aparece como 10%. Ajuste step, minValue e maxValue na mesma escala.
'use client';
import { I18nProvider } from 'react-aria-components';
import { NumberField } from '@/components/ui/number-field';
export default function NumberFieldPercent() {
return (
<I18nProvider locale="pt-BR">
{/* O valor é uma fração: 0,1 é exibido como 10% */}
<NumberField
label="Desconto à vista"
defaultValue={0.1}
minValue={0}
maxValue={0.5}
step={0.05}
formatOptions={{ style: 'percent' }}
description="Máximo de 50%."
className="w-64"
/>
</I18nProvider>
);
}Unidades
style: "unit" aceita as unidades do Intl.NumberFormat (meter, kilogram, minute, liter…).
Unidades de área como m² não existem no Intl — nesse caso, deixe a unidade no rótulo.
'use client';
import { I18nProvider } from 'react-aria-components';
import { NumberField } from '@/components/ui/number-field';
export default function NumberFieldUnits() {
return (
<I18nProvider locale="pt-BR">
<div className="flex w-64 flex-col gap-6">
<NumberField
label="Largura da fachada"
defaultValue={4.5}
minValue={0}
hideStepper
formatOptions={{ style: 'unit', unit: 'meter', maximumFractionDigits: 2 }}
description="Medida usada para calcular o letreiro."
/>
<NumberField
label="Peso do pacote"
defaultValue={1.5}
minValue={0.1}
step={0.1}
formatOptions={{ style: 'unit', unit: 'kilogram', maximumFractionDigits: 1 }}
/>
<NumberField
label="Duração da sessão"
defaultValue={60}
minValue={15}
maxValue={180}
step={15}
formatOptions={{ style: 'unit', unit: 'minute', unitDisplay: 'long' }}
/>
</div>
</I18nProvider>
);
}Validação
isRequired, minValue/maxValue e validate exibem a mensagem abaixo do campo. Clique em Calcular orçamento.
'use client';
import { I18nProvider } from 'react-aria-components';
import { Button } from '@/components/ui/button';
import { Form } from '@/components/ui/form';
import { NumberField } from '@/components/ui/number-field';
export default function NumberFieldValidation() {
return (
<I18nProvider locale="pt-BR">
<Form className="w-64 gap-4" onSubmit={(e) => e.preventDefault()}>
<NumberField label="Número de usuários" name="usuarios" isRequired minValue={1} />
<NumberField
label="Páginas do site"
name="paginas"
defaultValue={60}
validationBehavior="aria"
validate={(value) => (value > 50 ? 'Máximo de 50 páginas no plano atual.' : null)}
/>
<Button type="submit" className="self-start">
Calcular orçamento
</Button>
</Form>
</I18nProvider>
);
}Quando usar
- Use para quantidades e valores: preço, desconto, número de páginas, duração.
- Não use para identificadores como CPF, CNPJ, CEP ou telefone — eles são texto; use
Input. - Não use para escolher um valor aproximado num intervalo visual — use
Slider. - Informe limites com
minValue/maxValue: eles também bloqueiam os botões −/+ no limite.
API
NumberField
Aceita todas as props do NumberField do React Aria, mais:
Prop
Type