# Number Stepper

Enhance a native number input with increment controls. (Custom element.)

Reference: https://timeless.build/docs/components/number-stepper/

## Markup

```html
<ui-number-stepper aria-labelledby="quantity-label">
  <label id="quantity-label" for="quantity">Quantity</label>
  <button type="button" data-ui-part="decrement" aria-label="Decrease Quantity">−</button>
  <input id="quantity" type="number" value="2" min="1" max="10">
  <button type="button" data-ui-part="increment" aria-label="Increase Quantity">+</button>
</ui-number-stepper>
```

## Install

```js
import '@timelessui/components/css/tokens.css'
import '@timelessui/components/css/core/number-stepper.css'
import '@timelessui/components/css/themes/atmosphere/tokens.css'
import '@timelessui/components/css/themes/atmosphere/number-stepper.css'
import '@timelessui/components/register/ui-number-stepper'
```

A `register/` import is a side effect: it defines the element as the module evaluates, so it
has to run in code the browser loads. To register explicitly instead — to control the timing,
or to define into another window — call the function from the matching `define/` entry point,
which registers nothing on its own:

```js
import { defineNumberStepperElement } from '@timelessui/components/define/ui-number-stepper'
defineNumberStepperElement()
```

## Anatomy

Parts are authored in your own markup and identified by the selector below. Required parts
must be present for the component to work. Private `data-ui-internal-*` hooks are written by
the runtime and must never be authored.

| Part | Required | Selector | Purpose |
| --- | --- | --- | --- |
| `input` | Yes | `input[type='number']` | The native number input. `min`, `max`, and `step` come from it, and native validation keeps working. |
| `decrement` | Yes | `[data-ui-part~='decrement']` | Button that steps down. Give it an accessible name. |
| `increment` | Yes | `[data-ui-part~='increment']` | Button that steps up. Give it an accessible name. |

## Element API

Attributes above are the authoring surface. These are the DOM properties and events the
registered element adds once it upgrades.

### `<ui-number-stepper>`

This element adds no public properties. Configure it with its attributes.

| Event | Detail | Description |
| --- | --- | --- |
| `input` | `Event` | Native `input` event dispatched on the inner number input after each step. |
| `change` | `Event` | Native `change` event dispatched on the inner number input. |

## Styling

Root identity: `ui-number-stepper`.
Required stylesheets: `tokens.css`, `core/number-stepper.css`, `themes/atmosphere/tokens.css`, `themes/atmosphere/number-stepper.css`.

This component adds no custom properties of its own. Restyle it through the design tokens at https://timeless.build/docs/styling/theming/ or your own CSS.

Design tokens this component reads (11), global and set at the theme level: `--ui-bg-control-hover`, `--ui-bg-control-muted`, `--ui-disabled-opacity`, `--ui-fg`, `--ui-fg-muted`, `--ui-focus`, `--ui-font-mono`, `--ui-line`, `--ui-radius-md`, `--ui-space-2`, `--ui-space-3`.

## Accessibility

Keep the native elements, roles, and relationships shown in the markup. Timeless adds only the
state and keyboard coordination the platform does not already provide, and it never supplies
your accessible names — those depend on your content.

Follows the [Spinbutton pattern](https://www.w3.org/WAI/ARIA/apg/patterns/spinbutton/) from the ARIA Authoring Practices Guide.

Every key comes from the native `input[type="number"]`, which is already a spinbutton: Arrow Up and Arrow Down step by `step`, Page Up and Page Down step further where the platform provides it, and Home and End reach `min` and `max`. Timeless adds no keyboard handling and no ARIA on top, because there is nothing missing — it writes `role="group"` on the host so the two buttons and the field read as one control, which is why the host needs your accessible name. At a bound the corresponding button takes `aria-disabled="true"` rather than `disabled`: a button that goes inert while it is being pressed would otherwise take focus to `<body>` with it, so it stays focusable and does nothing.

## Before JavaScript runs

The markup above is complete and usable on its own: native controls submit, labels associate, and authored ARIA is already correct. Registration adds state synchronisation, focus management, and keyboard coordination on top of it.
