Getting StartedComponentsDesign TokensThemingTheme SynthesizerFrameworksAccessibilityUtilitiesServer RenderingBrowser SupportContributingChangelog App ShellAspect GridAuth ShellCenterContainerDashboard GridFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbar Anchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkMenubarNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkStepper NavTabsTop BarTree View AccordionAspect RatioAvatarAvatar GroupCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageImage CompareImage HotspotsInfinite ScrollLightboxMarqueeQR CodeScroll AreaSkeletonSpinnerStackVideoVirtual List Activity HeatmapAnimated NumberBadgeChartClockComparisonCountdown TimerData GridDescription ListDiffGaugeJSON TreeKanbanLevel MeterListMeterSparklineStatStepperTagTimelineUptimeValue CardWaveform BlockquoteCode BlockGradient TextHighlightKbdKeyboard MapMarkdownNumber FormatProseTerminalTextTime AgoTruncateTypewriter ButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerDate Range PickerFieldsetFile UploadFormHotkeyIcon ButtonImage CropperInline EditInputInput GroupKnobLabelMasked InputMulti SelectNumber InputPassword InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSignature PadSliderSortable ListSwitch GroupTag InputTextareaTheme ToggleTime PickerToggleTransfer ListTree Select AlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuConversationDialogDropdown MenuHover CardLoading OverlayNotification PanelPopoverProgressSheetToastTooltip
ARC UI ARC Radiant Components
v4.2 Docs Components Tokens Synthesizer
Getting StartedFrameworksServer Rendering Design TokensThemingTheme SynthesizerTypographyUtilities All ComponentsAccessibilityBrowser SupportChangelogContributingStats App ShellAspect GridAuth ShellCenterContainerDashboard GridFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbar Anchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkMenubarNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkStepper NavTabsTop BarTree View AccordionAspect RatioAvatarAvatar GroupCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageImage CompareImage HotspotsInfinite ScrollLightboxMarqueeQR CodeScroll AreaSkeletonSpinnerStackVideoVirtual List Activity HeatmapAnimated NumberBadgeChartClockComparisonCountdown TimerData GridDescription ListDiffGaugeJSON TreeKanbanLevel MeterListMeterSparklineStatStepperTagTimelineUptimeValue CardWaveform BlockquoteCode BlockGradient TextHighlightKbdKeyboard MapMarkdownNumber FormatProseTerminalTextTime AgoTruncateTypewriter ButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerDate Range PickerFieldsetFile UploadFormHotkeyIcon ButtonImage CropperInline EditInputInput GroupKnobLabelMasked InputMulti SelectNumber InputPassword InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSignature PadSliderSortable ListSwitch GroupTag InputTextareaTheme ToggleTime PickerToggleTransfer ListTree Select AlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuConversationDialogDropdown MenuHover CardLoading OverlayNotification PanelPopoverProgressSheetToastTooltip

Number Input

A numeric stepper input with decrement and increment buttons flanking a central text field, supporting min/max clamping, step increments, and keyboard shortcuts.

Components Number Input
input interactive
<arc-number-input>

Overview

NumberInput combines a native numeric text field with decrement and increment buttons to create a precise, user-friendly numeric stepper. The three elements are presented as a unified control with a shared border and rounded corners, where the buttons sit on either side of the input field separated by subtle inner borders. When the control receives focus, the entire border shifts to accent-primary with a focus ring, providing clear visual feedback. The component enforces value boundaries through automatic clamping. When `min` or `max` props are set, the value is clamped to stay within range, and the corresponding button becomes disabled and visually dimmed when the limit is reached. The `step` prop controls the increment granularity for both button clicks and keyboard interactions. Holding Shift while pressing arrow keys multiplies the step by 10, enabling quick large adjustments without repeated clicks. When a `label` is provided, it renders as an uppercase accent-font label above the control, connected to the input via a generated `id` and `for` attribute for accessibility. The events mirror the native control: typing fires `arc-input` alone on each keystroke, and the value commits with `arc-change` on blur or Enter. A stepper button click or an arrow key fires both, because each of those is an edit and a commit in one gesture. Every event carries the new value in its detail.

Guidelines

When to use

  • Use NumberInput when the user needs to enter or adjust an exact numeric value
  • Set `min` and `max` to prevent invalid values and provide clear boundary feedback
  • Choose a `step` that matches your data precision — 1 for integers, 0.1 for decimals
  • Provide a `label` so the input is properly announced by screen readers
  • Use the Shift+Arrow shortcut tip in help text for power users who need fast adjustments

When not to use

  • Do not use NumberInput for approximate values or large ranges — use Slider instead
  • Do not omit `min` and `max` when there are logical boundaries for the value
  • Do not set a `step` of 0 — it prevents the buttons from changing the value
  • Do not use NumberInput for non-numeric data like phone numbers — use a standard Input with a pattern
  • Avoid stacking many number inputs without labels — each one needs context for usability

Features

  • Inline decrement and increment buttons flanking a centered numeric text field
  • Automatic value clamping to `min` and `max` boundaries with buttons disabled at limits
  • Configurable `step` for increment granularity, with Shift+Arrow for 10x step multiplier
  • Focus-within styling applies accent-primary border and ring to the entire control group
  • Label rendered as uppercase accent-font text above the control with proper `for` association
  • Native `spinbutton` ARIA role with `aria-valuenow`, `aria-valuemin`, and `aria-valuemax`
  • Hides browser-native spin buttons for a clean cross-platform appearance
  • Disabled state at 40% opacity with pointer events blocked

Preview

Usage

This component requires JavaScript. No pure HTML/CSS version is available — use the Web Component directly or a framework wrapper.

<arc-number-input label="Quantity" value="3" min="1" max="99" step="1"></arc-number-input>
import { NumberInput } from '@arclux/arc-ui-react';

export default function Example() {
  return (
    <NumberInput label="Quantity" value={3} min={1} max={99} step={1} />
  );
}
<script setup>
import { NumberInput } from '@arclux/arc-ui-vue';
</script>

<template>
  <NumberInput label="Quantity" :value="3" :min="1" :max="99" :step="1" />
</template>
<script>
  import { NumberInput } from '@arclux/arc-ui-svelte';
</script>

<NumberInput label="Quantity" value={3} min={1} max={99} step={1} />
import { Component } from '@angular/core';
import { NumberInput } from '@arclux/arc-ui-angular';

@Component({
  imports: [NumberInput],
  template: `
    <arc-number-input label="Quantity" [value]="3" [min]="1" [max]="99" [step]="1"></arc-number-input>
  `,
})
export class MyComponent {}
import { NumberInput } from '@arclux/arc-ui-solid';

export default function Example() {
  return (
    <NumberInput label="Quantity" value={3} min={1} max={99} step={1} />
  );
}
import { NumberInput } from '@arclux/arc-ui-preact';

export default function Example() {
  return (
    <NumberInput label="Quantity" value={3} min={1} max={99} step={1} />
  );
}

API

value number 0
Current numeric value. Reflected as an attribute and updated on user interaction.
step number 1
Increment and decrement step size. Arrow keys use this value, Shift+Arrow uses 10x this value.
label string ''
Label text displayed above the control in uppercase accent font.
name string ''
disabled boolean false
Disables interaction, reducing opacity to 40% and blocking pointer events.
min number 0
Minimum allowed value. The decrement button is disabled when the value reaches this limit.
max number 0
Maximum allowed value. The increment button is disabled when the value reaches this limit.
readonly boolean false
Prevents value changes from typing, stepper buttons, and arrow keys while keeping the field focusable and its value submitted.
size 'sm' | 'md' | 'lg' 'md'
Control size. md is the default; sm and lg scale the field padding.
formAssociated boolean true
properties object { // flag(), unlike `disabled`. The exclusion in props.js is specifically // about form-associated *platform* semantics: a `disabled` content // attribute that is merely present makes the element actually disabled // per the HTML spec, and formDisabledCallback assigns the property back, // so no converter can win. Neither of these is platform-mapped — // `required` is enforced by _computeValidity() below and `readonly` by // each component's own interaction handlers — so the stock converter buys // nothing here and costs the usual bug: `required="false"` read as true, // blocking submission of a form the author meant to leave optional. // Finding #48's shape, across all 26 form controls at once. required: flag(false), readonly: flag(false), }
Lit merges static properties up the prototype chain, so every consumer gets these without declaring them. required participates in constraint validation below; readonly reflects for styling and is enforced by each component's interaction handlers (the mixin can't know which gestures mutate state).
autoValidates boolean true
Components that run their own constraint-validation logic (pattern checks, range checks) opt out of the automatic required sync by overriding this to false, and own the whole validity flag set instead.
form
validity
validationMessage
required boolean false

Methods

checkValidity() boolean
Whether the control currently satisfies its constraints, per the native constraint-validation API. Fires invalid on the element when it does not, and reports nothing to the user.
reportValidity() boolean
As checkValidity(), but also shows the browser's validation message against the control when it fails.

Events

arc-input detail: { value: number }
Fired on every edit, including each keystroke while typing. Use for live previews.
arc-change detail: { value: number }
Fired when the value is committed: blur or Enter after typing, or immediately on a stepper click or arrow key, which are edit and commit in one gesture.

See Also