0.1.0

Number Field

Number fields collect numeric input with increment/decrement steppers, locale formatting, and min/max constraints.

Try it

Usage

Set minValue, maxValue, and step to constrain input. Compose with RuiNumberFieldGroup and stepper buttons for the full pattern.

import {
  RuiNumberField,
  RuiNumberFieldGroup,
  RuiNumberFieldInput,
  RuiNumberFieldDecrementButton,
  RuiNumberFieldIncrementButton,
  RuiNumberFieldSteppers,
} from '@ecopages/radiant-ui/number-field';
 
<RuiNumberField value={3} minValue={0} maxValue={10} step={1}>
  <RuiNumberFieldGroup>
    <RuiNumberFieldInput />
    <RuiNumberFieldSteppers>
      <RuiNumberFieldDecrementButton />
      <RuiNumberFieldIncrementButton />
    </RuiNumberFieldSteppers>
  </RuiNumberFieldGroup>
</RuiNumberField>

Custom markup

<rui-number-field> coordinates any light-DOM tree that matches its query contract. The RuiNumberField helpers stamp these targets; they are not required.

import '@ecopages/radiant-ui/number-field';
 
<rui-number-field name="quantity" value={3} min-value={0} max-value={10}>
  <div class="rui-number-field__group" data-number-field-group>
    <input type="text" data-number-field-input data-rui-control data-rui-control-type="number" class="rui-number-field__input" />
    <button type="button" data-number-field-action="decrement" class="rui-number-field__stepper">−</button>
    <button type="button" data-number-field-action="increment" class="rui-number-field__stepper">+</button>
  </div>
</rui-number-field>

BEM classes are presentation-only. The host owns formatted input value and spinbutton aria-*. Set name on the host to submit the raw number with a native form (not the formatted display string).

Step and commit behavior

commitBehavior controls whether out-of-range typed values snap to bounds or reject on blur.

Disable scroll wheel

Set wheelDisabled to prevent accidental value changes when users scroll over a focused number field.

Theming

Number field surfaces map to semantic surface roles, never Tailwind palette steps:

PartCSS roles
Group (.rui-number-field__group)border, background, rounded-control
Input (.rui-number-field__input)on-background text
Steppers (.rui-number-field__steppers)border divider
Stepper (.rui-number-field__stepper)on-surface, surface hover, surface-container-low active
Focus / invalidfocus-ring / error

Geometry shares control tokens (--size-control-sm, --space-control-*, --radius-control, --text-control) with RuiInput and RuiButton so form rows align. Override at the theme layer, not in component CSS.

API

RuiNumberField is a custom element (<rui-number-field>). Standalone it renders the default input + stepper row; compose the view helpers for full control.

Attributes

AttributeTypeDefaultDescription
valuenumberCurrent value.
default-valuenumberInitial value when uncontrolled.
min-valuenumber-InfinityLower bound; steppers and arrow keys snap to it.
max-valuenumberInfinityUpper bound; steppers and arrow keys snap to it.
stepnumber1Increment/decrement and snap interval.
disabledbooleanfalseDisables input and steppers.
read-onlybooleanfalseBlocks editing; the value still displays formatted.
labelstring''Accessible name when there is no visible RuiLabel.
namestring''Form field name on this host. Submits the raw number, not the formatted display.
localestring''BCP 47 locale tag, or comma-separated fallback list.
format-optionsstring''JSON-serialized Intl.NumberFormatOptions.
commit-behaviorsnap · validatesnapBlur behavior after editing.
increment-aria-labelstringIncrementAccessible name for the increment stepper.
decrement-aria-labelstringDecrementAccessible name for the decrement stepper.
wheel-disabledbooleanfalseDisables scroll-wheel value changes.

Light-DOM contract

TargetRequiredHost writesAuthor owns
[data-number-field-input]yesid, role, inputmode, data-disabled, data-readonly, aria-valuemin, aria-valuemax, aria-valuenow, formatted valuetext input; stamp data-rui-control for field wiring
[data-number-field-action="decrement"]nodisabled, aria-labeldecrement button
[data-number-field-action="increment"]nodisabled, aria-labelincrement button
[data-number-field-group]no—presentation wrapper only

Nested hosts: none.

Events

EventDetailDescription
rui-change{ value: number }Emitted when a value is committed (blur, stepper, or keyboard).

View helpers

ComponentTarget stampedNotes
RuiNumberFielddefault group when children omittedIncludes input and steppers.
RuiNumberFieldGroup[data-number-field-group]Presentation only; not queried.
RuiNumberFieldInput[data-number-field-input]Always stamps data-rui-control.
RuiNumberFieldIncrementButton[data-number-field-action="increment"]Default label "Increment".
RuiNumberFieldDecrementButton[data-number-field-action="decrement"]Default label "Decrement".
RuiNumberFieldSteppersstepper column wrapperPresentation only.

CSS classes

Public BEM classes (documented via @cssclass):

ClassDescription
.rui-number-fieldRoot field wrapper.
.rui-number-field__groupControl-height bordered row.
.rui-number-field__inputBorderless text input.
.rui-number-field__steppersTrailing stepper column.
.rui-number-field__stepperIcon button cell (+ / −).

Theme roles

PartCSS variables consumed
Group--border, --background, --radius-control, --duration-normal
Input--on-background, --space-control-x, --space-control-y, --text-control
Steppers--size-control-sm
Stepper states--on-surface, --surface, --surface-container-low
Focus / invalid--focus-ring / --error

Accessibility

  • Stepper buttons need accessible names; "Increment" and "Decrement" are provided by default.
  • Announce min and max constraints in helper text when the valid range is not obvious.
  • Disabled fields should explain why editing is unavailable.