Number Field
An input specifically designed for numbers, complete with increment/decrement steppers, scrub area support, and advanced formatting.
import * as React from 'react'; import { NumberField } from 'gnome-ui/number-field'; import { ChevronUp, ChevronDown } from 'lucide-react'; export function NumberFieldDefault() { return ( <NumberField.Root defaultValue={10} className="flex flex-col gap-1.5 w-32"> <NumberField.Group className="flex h-10 w-full overflow-hidden rounded-xl border border-input bg-card text-foreground shadow-sm transition-colors focus-within:border-primary focus-within:outline focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-ring"> <NumberField.Input className="w-full bg-transparent px-3 py-2 text-sm outline-none placeholder:text-muted-foreground" /> <div className="flex flex-col border-l border-input"> <NumberField.Increment className="flex flex-1 items-center justify-center px-2 hover:bg-accent hover:text-accent-foreground disabled:opacity-50"> <Icons.ChevronUp className="size-3" strokeWidth={3} /> </NumberField.Increment> <NumberField.Decrement className="flex flex-1 items-center justify-center border-t border-input px-2 hover:bg-accent hover:text-accent-foreground disabled:opacity-50"> <Icons.ChevronDown className="size-3" strokeWidth={3} /> </NumberField.Decrement> </div> </NumberField.Group> </NumberField.Root> ); }
Anatomy
import { NumberField } from 'gnome-ui/number-field'; <NumberField.Root> <NumberField.ScrubArea> <NumberField.ScrubAreaCursor /> </NumberField.ScrubArea> <NumberField.Group> <NumberField.Decrement /> <NumberField.Input /> <NumberField.Increment /> </NumberField.Group> </NumberField.Root>
Examples
Formatting
You can pass Intl.NumberFormatOptions to the format prop to automatically format the input value. The steppers can also be placed side-by-side for a more horizontal layout.
import * as React from 'react'; import { NumberField } from 'gnome-ui/number-field'; import { Minus, Plus } from 'lucide-react'; export function NumberFieldFormatting() { return ( <NumberField.Root defaultValue={99} format={{ style: 'currency', currency: 'USD' }} className="flex flex-col gap-1.5 w-48" > <NumberField.Group className="flex h-10 w-full items-center overflow-hidden rounded-xl border border-input bg-card text-foreground shadow-sm transition-colors focus-within:border-primary focus-within:outline focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-ring"> <NumberField.Decrement className="flex h-full items-center justify-center border-r border-input px-3 hover:bg-accent hover:text-accent-foreground disabled:opacity-50"> <Icons.Minus className="size-4" strokeWidth={2.5} /> </NumberField.Decrement> <NumberField.Input className="w-full bg-transparent px-3 py-2 text-center text-sm outline-none placeholder:text-muted-foreground" /> <NumberField.Increment className="flex h-full items-center justify-center border-l border-input px-3 hover:bg-accent hover:text-accent-foreground disabled:opacity-50"> <Icons.Plus className="size-4" strokeWidth={2.5} /> </NumberField.Increment> </NumberField.Group> </NumberField.Root> ); }
Scrub Area
The ScrubArea component provides a label that users can click and drag horizontally or vertically to change the value smoothly without typing.
import * as React from 'react'; import { NumberField } from 'gnome-ui/number-field'; import { ArrowsRightLeft } from 'lucide-react'; export function NumberFieldScrub() { return ( <NumberField.Root defaultValue={50} className="flex flex-col gap-1.5 w-32"> <NumberField.ScrubArea className="group flex w-fit cursor-ew-resize select-none items-center gap-1.5 text-sm font-medium text-muted-foreground transition-colors hover:text-foreground"> <Icons.ArrowsRightLeft className="size-3.5" /> <label className="cursor-ew-resize">Adjust</label> <NumberField.ScrubAreaCursor className="rounded-full bg-primary/20 backdrop-blur-sm" /> </NumberField.ScrubArea> <NumberField.Group className="flex h-10 w-full overflow-hidden rounded-xl border border-input bg-card text-foreground shadow-sm transition-colors focus-within:border-primary focus-within:outline focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-ring"> <NumberField.Input className="w-full bg-transparent px-3 py-2 text-sm outline-none placeholder:text-muted-foreground" /> </NumberField.Group> </NumberField.Root> ); }
NumberFieldDecrement
A stepper button that decreases the field value when clicked.
Renders an <button> element.
Documentation: Base UI Number Field
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | (...) => string) | — | CSS class applied to the element, or a function that returns a class based on the component’s state. |
| render | ReactElement> | ComponentRenderFn | — | Allows you to replace the component’s HTML element with a different tag, or compose it with another component. Accepts a ReactElement or a function that returns the element to render. |
| nativeButton | boolean | true | Whether the component renders a native <button> element when replacing itvia the render prop.Set to false if the rendered element is not a button (e.g. <div>). |
NumberFieldGroup
Groups the input with the increment and decrement buttons.
Renders a <div> element.
Documentation: Base UI Number Field
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | (...) => string) | — | CSS class applied to the element, or a function that returns a class based on the component’s state. |
| render | ReactElement> | ComponentRenderFn | — | Allows you to replace the component’s HTML element with a different tag, or compose it with another component. Accepts a ReactElement or a function that returns the element to render. |
NumberFieldIncrement
A stepper button that increases the field value when clicked.
Renders an <button> element.
Documentation: Base UI Number Field
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | (...) => string) | — | CSS class applied to the element, or a function that returns a class based on the component’s state. |
| render | ReactElement> | ComponentRenderFn | — | Allows you to replace the component’s HTML element with a different tag, or compose it with another component. Accepts a ReactElement or a function that returns the element to render. |
| nativeButton | boolean | true | Whether the component renders a native <button> element when replacing itvia the render prop.Set to false if the rendered element is not a button (e.g. <div>). |
NumberFieldInput
The native input control in the number field.
Renders an <input> element.
Documentation: Base UI Number Field
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | (...) => string) | — | CSS class applied to the element, or a function that returns a class based on the component’s state. |
| aria-roledescription | string | 'Number field' | A string value that provides a user-friendly name for the role of the input. |
| render | ReactElement> | ComponentRenderFn | — | Allows you to replace the component’s HTML element with a different tag, or compose it with another component. Accepts a ReactElement or a function that returns the element to render. |
NumberFieldRoot
Groups all parts of the number field and manages its state.
Renders a <div> element.
Documentation: Base UI Number Field
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | (...) => string) | — | CSS class applied to the element, or a function that returns a class based on the component’s state. |
| defaultValue | number | — | The uncontrolled value of the field when it’s initially rendered. To render a controlled number field, use the value prop instead. |
| id | string | — | The id of the input element. |
| render | ReactElement> | ComponentRenderFn | — | Allows you to replace the component’s HTML element with a different tag, or compose it with another component. Accepts a ReactElement or a function that returns the element to render. |
| value | number | — | The raw numeric value of the field. |
| disabled | boolean | false | Whether the component should ignore user interaction. |
| step | number | "any" | 1 | Amount to increment and decrement with the buttons and arrow keys, or to scrub with pointer movement in the scrub area. To always enable step validation on form submission, specify the min prop explicitly in conjunction with this prop.Specify step="any" to always disable step validation. |
| name | string | — | Identifies the field when a form is submitted. |
| required | boolean | false | Whether the user must enter a value before submitting a form. |
| readOnly | boolean | false | Whether the user should be unable to change the field value. |
| inputRef | Ref<HTMLInputElement> | — | A ref to access the hidden input element. |
| locale | LocalesArgument | — | The locale of the input element. Defaults to the user's runtime locale. |
| onValueChange | (...) => void | — | Callback fired when the number value changes. The eventDetails.reason indicates what triggered the change:- 'input-change' for parseable typing or programmatic text updates- 'input-clear' when the field becomes empty- 'input-blur' when formatting (and clamping, if enabled) occurs on blur- 'input-paste' for paste interactions- 'keyboard' for keyboard input- 'increment-press' / 'decrement-press' for button presses on the increment and decrement controls- 'wheel' for wheel-based scrubbing- 'scrub' for scrub area drags |
| max | number | — | The maximum value of the input element. |
| min | number | — | The minimum value of the input element. |
| format | NumberFormatOptions | — | Options to format the input value. |
| allowOutOfRange | boolean | false | When true, direct text entry may be outside the min/max range without clamping,so native range underflow/overflow validation can occur. Step-based interactions (keyboard arrows, buttons, wheel, scrub) still clamp. |
| smallStep | number | 0.1 | The small step value of the input element when incrementing while the meta key is held. Snaps to multiples of this value. |
| largeStep | number | 10 | The large step value of the input element when incrementing while the shift key is held. Snaps to multiples of this value. |
| allowWheelScrub | boolean | false | Whether to allow the user to scrub the input value with the mouse wheel while focused and hovering over the input. |
| snapOnStep | boolean | false | Whether the value should snap to the nearest step when incrementing or decrementing. |
| onValueCommitted | (...) => void | — | Callback function that is fired when the value is committed. It runs later than onValueChange, when:- The input is blurred after typing a value. - The pointer is released after scrubbing or pressing the increment/decrement buttons. It runs simultaneously with onValueChange when interacting with the keyboard.Warning: This is a generic event not a change event. |
NumberFieldScrubArea
An interactive area where the user can click and drag to change the field value.
Renders a <span> element.
Documentation: Base UI Number Field
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | (...) => string) | — | CSS class applied to the element, or a function that returns a class based on the component’s state. |
| render | ReactElement> | ComponentRenderFn | — | Allows you to replace the component’s HTML element with a different tag, or compose it with another component. Accepts a ReactElement or a function that returns the element to render. |
| direction | "horizontal" | "vertical" | 'horizontal' | Cursor movement direction in the scrub area. |
| pixelSensitivity | number | 2 | Determines how many pixels the cursor must move before the value changes. A higher value will make scrubbing less sensitive. |
| teleportDistance | number | — | If specified, determines the distance that the cursor may move from the center of the scrub area before it will loop back around. |
NumberFieldScrubAreaCursor
A custom element to display instead of the native cursor while using the scrub area.
Renders a <span> element.
This component uses the Pointer Lock API, which may prompt the browser to display a related notification. It is disabled in Safari to avoid a layout shift that this notification causes there.
Documentation: Base UI Number Field
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | (...) => string) | — | CSS class applied to the element, or a function that returns a class based on the component’s state. |
| render | ReactElement> | ComponentRenderFn | — | Allows you to replace the component’s HTML element with a different tag, or compose it with another component. Accepts a ReactElement or a function that returns the element to render. |
Navigation Menu
A collection of links for navigating websites. The navigation menu provides a container for linking to different sections or pages, with support for nested popups and smooth sizing transitions.
Pagination
A pagination component for navigating between pages of content. Composed of `Pagination`, `PaginationContent`, `PaginationItem`, `PaginationButton`, `PaginationPrevious`, `PaginationNext`, and `PaginationEllipsis`.