Number field
A whole number, such as a count; empty while nothing is typed.
Installation
npx shadcn@latest add @formdef/number-fieldRegister it under widgets in lib/formdef/index.tsx, as widgets: { number: NumberField }.
Usage
The widget serves number | undefined: an empty input is undefined, not 0. It finds a field
whose schema input is number, optional or not.
export const = createForm({
: .({ : .().().(1).(8).() }),
: { : },
fields: {
guests: { : 'number', : { : 'Guests', : 1, : 8, : 1 } },
},
})min, max and step go to the <input type="number">, where the arrow keys and the spin
buttons respect them. The schema still decides what is valid.
Not for amounts
The number field is for counts and whole numbers. An amount or any other decimal belongs in a
text field with inputMode: 'decimal': an <input type="number">
turns a typed comma into a dot or drops it, so a German amount cannot be entered.
Props
Prop
Type
Source
import { type FieldOf, fieldParts } from '@formdef/core'
import type { ComponentProps } from 'react'
import { FieldFrame } from '@/components/formdef/field-frame'
import { Input } from '@/components/ui/input'
import type { FieldLabels } from '@/lib/formdef/field-labels'
type Attrs = Pick<
ComponentProps<'input'>,
| 'className'
| 'placeholder'
| 'autoComplete'
| 'autoFocus'
| 'disabled'
| 'readOnly'
| 'required'
| 'min'
| 'max'
| 'step'
>
type NumberFieldProps = FieldOf<number | undefined> & FieldLabels & Attrs
export const NumberField = ({
field,
label,
labelAside,
description,
...attrs
}: NumberFieldProps) => {
const parts = fieldParts(field, { description })
const value = field.state.value ?? ''
return (
<FieldFrame
parts={parts}
label={label}
labelAside={labelAside}
description={description}
disabled={attrs.disabled}
>
<Input
{...attrs}
{...parts.control}
type="number"
value={value}
onChange={(event) =>
field.handleChange(event.target.value === '' ? undefined : event.target.valueAsNumber)
}
/>
</FieldFrame>
)
}