# @19h47/spinbutton

> Spinbutton

Latest version **6.0.0** (published 2026-08-30) · ISC license · 0 weekly downloads

## Install

```sh
npm install @19h47/spinbutton
pnpm add @19h47/spinbutton
yarn add @19h47/spinbutton
bun add @19h47/spinbutton
```

## Health

**Score 55/100 (C)** — status: active.

Positive: esm support; no vulnerabilities; recently updated.

Warnings: low downloads; no types.

## Facts

| | |
|---|---|
| Version | 6.0.0 |
| Published | 2026-08-30 |
| First published | 2020-02-06 |
| Weekly downloads | 0 |
| License | ISC |
| TypeScript types | none |
| Module format | ESM + CommonJS |
| Dependencies | 0 |
| Unpacked size | 18.5 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 1 |
| Author | Jérémy Levron |
| Maintainers | 19h47 |
| Keywords | ES6 |

## Links

- npm: https://www.npmjs.com/package/@19h47/spinbutton
- Repository: https://github.com/19h47/19h47-spinbutton
- Homepage: https://github.com/19h47/19h47-spinbutton#readme
- Issues: https://github.com/19h47/19h47-spinbutton/issues
- npm.io page: https://npm.io/package/@19h47/spinbutton

## Recent versions

- 6.0.0 (latest) — 2026-08-30
- 5.4.3 — 2025-05-03
- 5.3.2 — 2025-04-30
- 5.2.2 — 2025-04-28
- 5.2.1 — 2025-04-28
- 5.1.1 — 2025-04-27
- 5.1.0 — 2025-04-27
- 5.0.0 — 2025-04-26
- 4.0.5 — 2025-04-23
- 4.0.4 — 2025-04-23
- 4.0.3 — 2025-04-22
- 4.0.2 — 2025-04-22
- 4.0.1 — 2025-04-22
- 4.0.0 — 2025-04-22
- 3.0.0 — 2025-03-26
- … 22 more at https://npm.io/package/@19h47/spinbutton/versions

## README

[![](https://img.shields.io/npm/v/@19h47/spinbutton)](https://www.npmjs.com/package/@19h47/spinbutton)
[![](https://img.shields.io/npm/dm/@19h47/spinbutton)](https://www.npmjs.com/package/@19h47/spinbutton)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/19h47/19h47-spinbutton)

# @19h47/spinbutton

A spinbutton is an input widget that restricts its value to a set or range of discrete values. It provides an accessible, keyboard-navigable interface for numerical input that maintains value constraints, internationalizes `aria-valuetext` with [Intl.PluralRules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules), and emits events when values change.

## Installation

```bash
pnpm add @19h47/spinbutton
```

Also works with `npm` / `yarn` / `bun`.

### Manual Download

You can also download the component directly from the GitHub repository at [https://github.com/19h47/19h47-spinbutton](https://github.com/19h47/19h47-spinbutton) and include the distributed files in your project.

## DOM structure

The Spinbutton requires a specific HTML structure to function properly:

The spinbutton is a `div` element with the role of `spinbutton`. It contains two buttons for increasing and decreasing the value, and an input field for displaying the current value.

```html
<div role="spinbutton" aria-valuemin="0" aria-valuemax="100" aria-valuenow="10">
	<button class="js-decrease" tabindex="-1" aria-label="decrease" type="button">-</button>

	<input type="text" />

	<button class="js-increase" tabindex="-1" aria-label="increase" type="button">+</button>

	<div class="visually-hidden" aria-live="polite" aria-atomic="true"></div>
</div>
```

The live region is optional. If it is in the markup, the script updates its text; it is never created or styled by JavaScript.

## JavaScript

Here is a simple example of how to use the spinbutton.

```javascript
import Spinbutton from '@19h47/spinbutton';

const $element = document.querySelector('[role="spinbutton"]');
const spinbutton = new Spinbutton($element);

spinbutton.init();
```

## Event Handling

The Spinbutton component emits a Spinbutton.change event when the value changes:

| Event             | Args  | Description                       |
| ----------------- | ----- | --------------------------------- |
| Spinbutton.change | value | Return the current activate value |

Here is an example of how to use the `Spinbutton.change` event.

```javascript
import Spinbutton from '@19h47/spinbutton';

const $element = document.querySelector('[role="spinbutton"]');
const spinbutton = new Spinbutton($element);

spinbutton.init();

spinbutton.addEventListener('Spinbutton.change', event => {
	console.log(event.detail.value); // Return the current activate value
});
```

## Configuration Options

The spinbutton accepts the following options. They can be set as data attributes on the `div` or passed when creating the instance.

| Option  | Type   |                                                          | Default | Attributes              |
| ------- | ------ | -------------------------------------------------------- | ------- | ----------------------- |
| `step`  | number | The step value to increase or decrease the value.        | 1       | `data-spinbutton-step`  |
| `delay` | number | The delay in milliseconds before the event is triggered. | 20      | `data-spinbutton-delay` |

Example with options:

```javascript
import Spinbutton from '@19h47/spinbutton';
const $element = document.querySelector('[role="spinbutton"]');
const spinbutton = new Spinbutton($element, { step: 5, delay: 100 });
spinbutton.init();
```

## Keyboard Support

The spin buttons provide the following keyboard support described in the [spinbutton design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/spinbutton/).

| Key        | Function                                                             |
| ---------- | -------------------------------------------------------------------- |
| Down Arrow | Decreases value 1 (or step option if given) step.                    |
| Up Arrow   | Increases the value 1 (or step option if given) step.                |
| Page Down  | Decreases the value 5 (or step option multiply by 5 if given) steps. |
| Page Up    | Increases the value 5 (or step option multiply by 5 if given) steps. |
| Home       | Decreases to mimimum value (if given).                               |
| End        | Increases to maximum value (if given).                               |

## Role, Property, State, and Tabindex Attributes

The spinbutton uses the following ARIA roles, properties, and states. The `aria-valuenow` attribute is updated when the value changes. The `aria-valuemin` and `aria-valuemax` attributes are used to define the minimum and maximum values of the spinbutton.

| Role         | Attribute        | Element | Usage                                         |
| ------------ | ---------------- | ------- | ----------------------------------------------|
| `spinbutton` |                  | `div`   | Identifies the `div` element as a spinbutton. |
| `spinbutton` | `aria-valuemin`  | `div`   | The minimum value of the spinbutton.          |
| `spinbutton` | `aria-valuemax`  | `div`   | The maximum value of the spinbutton.          |
| `spinbutton` | `aria-valuenow`  | `div`   | The current value of the spinbutton.          |
| `spinbutton` | `aria-valuetext` | `div`   | Spoken value, from `lang` + `data-spinbutton-text`. |

## Customization Examples

### Step Size

You can customize the step size:

```html
<div role="spinbutton" data-spinbutton-step="5" aria-valuemin="5" aria-valuemax="50" aria-valuenow="5">
    <!-- buttons and input -->
</div>
```

### Dynamic Control

You can dynamically change the minimum, maximum, and current values:

```javascript
// Set new minimum value
spinbutton.setMin(10);

// Set new maximum value
spinbutton.setMax(200);

// Set new value
spinbutton.setValue(50);
```

## Internationalization

`aria-valuetext` is formatted with [Intl.PluralRules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules). Nothing is hardcoded in English: the locale is the closest [lang](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/lang) attribute (`<html lang="fr">`, or `lang` on the spinbutton), and the words come from `data-spinbutton-text`.

Without that attribute, the value text is just the number (`0`, `1`, `2`).

Keys are [CLDR plural categories](https://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html): `one`, `other`, and `zero` / `two` / `few` / `many` when the language needs them.

### English

`0` and `2+` select `other`. `1` selects `one`.

```html
<div lang="en" role="spinbutton" data-spinbutton-text='{"one":"barrel","other":"barrels"}' aria-valuemin="0" aria-valuemax="100" aria-valuenow="0">
	<!-- buttons and input -->
</div>
```

| `aria-valuenow` | `aria-valuetext` |
| --------------- | ---------------- |
| `0`             | `0 barrels`      |
| `1`             | `1 barrel`       |
| `2`             | `2 barrels`      |

### French

`0` and `1` select `one`. `2+` selects `other`.

```html
<div lang="fr" role="spinbutton" data-spinbutton-text='{"one":"tonneau","other":"tonneaux"}' aria-valuemin="0" aria-valuemax="100" aria-valuenow="0">
	<!-- buttons and input -->
</div>
```

| `aria-valuenow` | `aria-valuetext` |
| --------------- | ---------------- |
| `0`             | `0 tonneau`      |
| `1`             | `1 tonneau`      |
| `2`             | `2 tonneaux`     |

## References

- [Spinbutton Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/spinbutton/)
- [Intl.PluralRules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules)
- [CLDR Language Plural Rules](https://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html)

---
_Source: https://npm.io/package/@19h47/spinbutton · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
