Skip to content
TopClass UI

Number field

A number between known bounds, typed or stepped. A hidden input carries the plain number, so the form submits before hydration.

client - size not measured yet

Number field

client - size not measured yet

A number between known bounds, typed or stepped. A hidden input carries the plain number, so the form submits before hydration.

Install

Try it

size
invalid
fullWidth
min
max

The code

number-field.tsx
import { NumberField } from 'topclassui/number-field'

<div className="grid justify-items-start gap-2">
  <label htmlFor="number-field-playground-guests" className="text-sm text-body">Guests</label>
  <NumberField id="number-field-playground-guests" defaultValue={2} />
</div>

min, max and step are clamped at runtime, so a typed or passed value cannot break the field.

Every state

4 states

Import from the package

topclassui/number-field
import { NumberField } from 'topclassui/number-field'

Install once:npm i topclassui@beta zod

Examples

  • For a count or an amount between known bounds: guests, seats, hours. Nothing bounds it by a count of characters.
  • The form receives the plain number, never the formatted text: 1234.5, not 1,234.5. An empty field sends an empty value.
  • A decimal needs a step it fits: with the default step of 1, a value of 12.5 fails the browser's check. Use 0.5 or any.
  • The field formats with the provider's locale and numbering system, so the server and the browser print the same text. Arabic-Indic digits are read in any locale.
  • A stepper at its limit is disabled and dimmed. The steppers keep their 24px, 44px under a touch pointer, so a narrow field takes the room from the number.
basic
limits
form
sizes
row
In Arabic, right to left

Props

The props of NumberField
PropTypeDefaultLimitsDescription
aria-labelstring--The name read out when no visible label names the control.
aria-labelledbystring--The id of the visible text that names the control.
idstring--The id a <label htmlFor> points at.
classNamestring--Merged last, so a consumer class wins a conflict with the field's own.
fullWidthbooleanfalse-Fills the width of its parent instead of taking the width of an Input.
invalidbooleanfalse-Marks the value as wrong: sets aria-invalid on the input, and the line of the field turns to danger and thickens.
maxnumber, min -1000000000000000, max 1000000000000000-min -1000000000000000, max 1000000000000000The largest value. End goes to it; a default or a value over it is lowered to it. Clamped to 1e15; NaN reads as none, and under min it is raised to min.
minnumber, min -1000000000000000, max 1000000000000000-min -1000000000000000, max 1000000000000000The smallest value. Home goes to it; a default or a value under it is raised to it. Clamped to -1e15; NaN reads as none.
placeholderstring--Shown in the input while it is empty.
refRef<HTMLDivElement>--The root element, the <div> that owns the width.
sizexs | sm | md | lg | xl | custom"md"-The control scale: the height of the field and its type step; custom emits no size classes.
stepunknown1-What an arrow key and a stepper add or take away, and the step the form validates against; any turns that check off. NaN reads as 1.

Keyboard and accessibility

The keyboard of NumberField
KeysWhat it does
ArrowUpAdds one step; with Shift it adds 10, with Alt 0.1.
ArrowDownTakes one step away; with Shift 10, with Alt 0.1.
HomeGoes to the minimum, when one is set.
EndGoes to the maximum, when one is set.
TabMoves past the field: the steppers are not tab stops.
  • A name is required: id for a <label htmlFor>, or aria-label, or aria-labelledby. They land on the visible input.
  • The steppers are named in the provider's language, and they are not tab stops: the arrow keys do the same from the input.
  • invalid sets aria-invalid on the input, and the line of the field turns to danger and thickens.

Right to left

Increase sits at the left and the number stays left to right. Its digits follow the provider's numbering system.

Server and client

A client component: it renders on the server and hydrates in the browser.

Files: index.tsx, client.tsx.

On the chip: client - size not measured yet.