Skip to content
NewService Map: 30 components for hosts, ports and routes
<hf-number>Custom elementInputsForm controlFree

Number stepper

Integer stepper whose number rolls over a dotted wash; holding a button repeats faster, and stepping past a limit shakes and flashes red.

View as Markdown
<hf-number>

Tryhold the plus button.

Playground

Change a prop and the component updates. Props marked live animate to the new value; the others rebuild the element.

Loading <hf-number>
Props
valuelive
minremounts
maxremounts
labelremounts
priceremounts
currencyremounts
unitremounts
nameremounts
<HfNumber
  value={12}
  min={1}
  max={50}
  label="Seats"
  price={24}
  currency="€"
  name="seats"
/>

Installation

pnpm dlx shadcn@latest add @lumesec/hf-number
First timeRegister the @lumesec registry once, or install by URL+

Adds @lumesec to your components.json:

pnpm dlx shadcn@latest registry add @lumesec=https://elements.lumesec.ai/r/{name}.json

Or skip the setup and install by URL:

npx shadcn@latest add https://elements.lumesec.ai/r/hf-number.json

Usage

import { HfNumber } from "@/components/lumesec/hf-number";

export function Example() {
  return (
    <HfNumber name="seats" label="Seats" value={12} min={1} max={50} price={24} />
  );
}

Behaviour

The number rolls up or down over a dotted wash, and a scan line crosses the dots on every step. Hold a button to repeat faster, with heat and sparks building up; bumping the limit flashes red. Click the number to type.

API reference

Attributes

valueReact propvalueTypenumberDefault5

Current value, rounded and clamped to min–max. Observed: a change rolls to the new number. Reflects the current value.

minReact propminTypenumberDefault1

Lowest allowed value.

maxReact propmaxTypenumberDefault50

Highest allowed value.

labelReact proplabelTypestringDefaultSeats

Label text, also used as the field's aria-label.

priceReact proppriceTypenumber

Unit price. When set, the line below reads <value> × <currency><price> = <currency><total> / month.

currencyReact propcurrencyTypestringDefault€

Currency symbol used with price.

unitReact propunitTypestring

Text shown below the stepper when price is not set.

nameReact propnameTypestring

Form field name used when the element is inside a form.

Events

Events bubble and cross the shadow boundary unless the description says otherwise.

inputReact proponInputDetail{ value: number }

Fires on each change from the buttons, keys, typed entry or the value attribute.

changeReact proponChangeDetail{ value: number }

Fires 300 ms after the last input, so holding a button produces one change.

Properties

valueTypenumber

Current value. Setting it writes the value attribute.

min (read-only)Typenumber

The min attribute, or 1.

max (read-only)Typenumber

The max attribute, or 50.

form (read-only)TypeHTMLFormElement | null

The owning form, from ElementInternals.

name (read-only)Typestring | null

The name attribute. There is no setter; set the attribute instead.

Keyboard

KeysAction
ArrowUp / ArrowDownIn the number field: add or subtract 1.
PageUp / PageDownIn the number field: add or subtract 10. If that would pass min or max, the value stays and the field flashes red.
EnterIn the number field: commit the typed number and leave the field.
Enter / SpaceOn the − or + button: step by 1.

Accessibility

  • The number is an <input> with role="spinbutton", inputmode="numeric", aria-valuenow, aria-valuemin, aria-valuemax and an aria-label from label.
  • The − and + buttons have aria-label Decrease and Increase and are disabled at the limits.
  • The price or unit line below is an aria-live="polite" region.
  • The visible number is text marked aria-hidden, because the spinbutton already exposes the value; while the input has focus, its own text replaces it. The wash and sparks are on an aria-hidden canvas.
  • Form-associated through ElementInternals.
  • Submits the integer as a string under name. There is no validation, and form reset and disabled are not handled.
  • Reduced motion: the number and the line below change without rolling, and the scan line, shake and sparks are skipped; the red flash and heat tint remain.

Theming

The element reads your shadcn theme tokens through its shadow root, so light and dark follow your theme. The accent comes from --lumesec. See Theming.

This component reads --border, --card, --foreground, --lumesec, --muted and --muted-foreground.

To restyle only LumeSec elements, set the matching --ui-* overrides: --ui-accent, --ui-border, --ui-fg, --ui-mono, --ui-muted, --ui-raised and --ui-surface.

Notes

  • Holding − or + repeats after 420 ms, speeding up from 160 ms to 35 ms per step. While a button is held, the number and the line below swap without rolling.
  • Clicking the number focuses the field for typing. The typed text is parsed as an integer and clamped when the field loses focus.
  • Programmatic changes to value fire input and change, the same as user changes.
  • While typing, the inner field's native input events stay inside the shadow root; only the element's own input and change events, with value in detail, reach the host.
  • The host is inline-block; the buttons and number area are 40px tall. The number is set in the mono font with tabular figures.

Was this page helpful?