Tessina UI
ConfiguratorGitHubIntroduction
InstallationUsageTheming
ComponentsAccordionAction SheetAlertAlertDialogArea ChartAspectRatioAvatarBadgeBannerBar ChartBottom NavBreadcrumbButtonButtonGroupCalendarCardCarouselChartChatBubbleCheckboxChipCodeBlockCollapsibleColor PickerComboboxCommandContainerContextMenuDate PickerDividerDrawerDropdown MenuEmptyStateFABFieldFieldsetFile UploadFile Upload 2FlexFormGridHoverCardIconButtonLabelLine ChartLinkMenubarMeterModalNavigation MenuNumberFieldOTP InputPaginationPie ChartPopoverProgressPromptInputRadar ChartRadial ChartRadioRatingScroll AreaSearchSegmentedControlSelectShortcutSidebarSkeletonSliderSpacerSpinnerSplit ButtonStackStatusStepperSurfaceSwitchTableTabsTextareaTime PickerToastToggleButtonToggleGroupToolbarTooltipTop Header DesktopTop Header Mobile
Contributing
Components

NumberField

Numeric form input with stacked, split, inline or no increment/decrement buttons. Five sizes, five rounded values, full intent palette, three label positions, prefix/suffix slots, locale-aware formatting via Intl.NumberFormat, and LTR/RTL support.

Playground

Installation

pnpm add @tessinaui/ui

Usage

import { NumberField } from "@tessinaui/ui";
{/* Basic uncontrolled */}
<NumberField defaultValue={0} />

{/* Controlled */}
<NumberField value={qty} onValueChange={setQty} min={0} max={99} />

{/* Quantity selector with split buttons */}
<NumberField buttonsPlacement="split" defaultValue={1} min={1} max={10} />

{/* Currency input with locale formatting */}
<NumberField
  defaultValue={1299.99}
  step={0.01}
  format={{ style: "currency", currency: "USD" }}
  locale="en-US"
/>

{/* Percent input */}
<NumberField
  defaultValue={0.245}
  step={0.001}
  format={{ style: "percent", minimumFractionDigits: 1 }}
/>

{/* With label + supporting text + intent */}
<NumberField
  label="Quantity"
  intent="error"
  supportingText="Out of stock"
  required
  defaultValue={0}
/>

{/* Prefix / suffix slots */}
<NumberField
  defaultValue={75}
  suffix={<span className="px-3 py-2 bg-secondary rounded-full">kg</span>}
/>

{/* RTL */}
<NumberField dir="rtl" label="الكمية" defaultValue={1} />

Examples

Default

A labelled numeric input with stacked stepper buttons.

Buttons placement

Step buttons can be stacked, split, inline, or hidden with none.

Sizes

Five sizes from xs to xl.

Intents

Colour the border, focus ring, and supporting text with error, warning, success, or info.

Label positions

Place the label outside-top, inside, or outside-left.

Locale-aware formatting

Pass format to render currency, percent, or compact values via Intl.NumberFormat.

NumberField vs Stepper

The two components solve different problems:

NumberFieldStepper
PurposeForm input — user types or steps a valueCompact counter — user picks a value with buttons
InputEditable text field with keyboard / paste supportNo input; value is read-only display
AffordancesLabel, supporting text, prefix/suffix, error statesLabel + supporting text only
Typical use"Price", "Age", "Weight" form fieldsQuantity selector in a cart row

If users can type the value, use NumberField. If they always pick from a small range with +/-, use Stepper.

API Reference

Props

PropTypeDefaultDescription
valuenumber | null—Controlled value
defaultValuenumber—Uncontrolled initial value
minnumber—Minimum value (decrement disabled at min)
maxnumber—Maximum value (increment disabled at max)
stepnumber | "any"1Amount per increment / decrement
smallStepnumber0.1Step when Meta key is held
largeStepnumber10Step when Shift key is held
snapOnStepbooleanfalseSnap to nearest step on increment / decrement
formatIntl.NumberFormatOptions—Locale-aware formatting (currency, percent, compact, decimals)
localeIntl.LocalesArgumentruntimeBCP-47 locale tag
allowWheelScrubbooleanfalseScrub the value with the mouse wheel while focused
allowOutOfRangebooleanfalseDirect text entry can exceed min / max for native validation
onValueChange(value, eventDetails) => void—Called whenever the value changes
onValueCommitted(value, eventDetails) => void—Called on blur / pointer release / keyboard commit
namestring—HTML form name
requiredbooleanfalseMark required (asterisk in label, native validation)
disabledbooleanfalseDisable all interaction
readOnlybooleanfalseValue visible but not editable
size"xs" | "sm" | "md" | "lg" | "xl""md"Field size
rounded"none" | "sm" | "md" | "lg" | "full""full"Container border radius
intent"none" | "error" | "warning" | "success" | "info""none"Border colour and supporting-text colour
labelstring—Visible label
labelPosition"outside-top" | "inside" | "outside-left""outside-top"Where the label sits
infoTextstring—Small info text rendered next to the label
supportingTextstring—Helper / validation text below the field, coloured by intent
prefixReactNode—Content rendered outside the field on the leading edge
suffixReactNode—Content rendered outside the field on the trailing edge
placeholderstring—Input placeholder
buttonsPlacement"stacked" | "split" | "inline" | "none""stacked"Layout of the increment / decrement buttons
incrementLabelstring"Increase"aria-label for the + button
decrementLabelstring"Decrease"aria-label for the − button
dir"ltr" | "rtl"inheritedText direction
idstringautoid of the underlying input
inputRefRef<HTMLInputElement>—Ref to the underlying input element
inputModestringautoMobile keyboard hint — numeric for integers, decimal otherwise
wrapperClassNamestring—Class on the outermost wrapper
containerClassNamestring—Class on the bordered container
classNamestring—Class on the <input> itself

Buttons placement

PlacementDescription
stackedTwo stacked chevrons on the trailing edge with a vertical divider. Each button is half the input height.
split− on the leading edge, + on the trailing edge. Each button is square and full-height.
inline− and + side-by-side on the trailing edge. Both square, both full-height.
noneNo visible buttons. Keyboard arrows and scroll wheel still work.

Intents

Same palette as Field — affects border, focus ring colour, and supporting-text colour.

IntentBorderFocus ringSupporting text
noneborder-borderring-ringtext-muted-foreground
errorborder-errorring-errortext-error
warningborder-warningring-warningtext-warning
successborder-successring-successtext-success
infoborder-inforing-infotext-info

Keyboard

KeyAction
↑ / ↓Increment / decrement by step
Shift + ↑ / Shift + ↓Increment / decrement by largeStep
Meta + ↑ / Meta + ↓Increment / decrement by smallStep
Page Up / Page DownIncrement / decrement by largeStep
Home / EndJump to min / max (when set)

Notes

  • Controlled vs uncontrolled: pass value for controlled, defaultValue for uncontrolled. The value can be null when the input is empty.
  • Locale formatting: passing format runs the value through Intl.NumberFormat — currencies, percentages, compact notation, and custom decimal places all work out of the box.
  • Scroll-wheel scrub: opt-in via allowWheelScrub. When enabled, scrolling over a focused field changes the value.
  • RTL: dir="rtl" is supported. Stacked / inline buttons stay on the trailing edge; split places + on the visual right and − on the visual left, matching standard RTL number-input conventions.
  • Accessibility: built on @base-ui/react/number-field. The hidden input is a real <input type="number"> so HTML form submission, native validation, and assistive technologies behave correctly.
  • Form submission: pass name to include the value in standard form submissions.

Navigation Menu

A full top-bar navigation pattern — logo, centre menu with mega-menu popups, and right-aligned action slots for language selector and auth CTAs. Ships two desktop trigger treatments (`pill`, `underline`), a `mode="mobile"` variant with a right-side drawer + submenu drill-in, richer mega-menu rows (tag + badge), and a theme-aware logo that swaps between light and dark sources. Built on @base-ui/react with 5 sizes, 5 rounded options, and LTR/RTL support.

OTP Input

One-time password input with individual digit cells. Supports three visual variants, five sizes, five intents, masking, separator groups, numeric/alphanumeric/alphabetic input types, and full RTL/LTR support.

On this page

PlaygroundInstallationUsageExamplesDefaultButtons placementSizesIntentsLabel positionsLocale-aware formattingNumberField vs StepperAPI ReferencePropsButtons placementIntentsKeyboardNotes