Inputs

Number Field

Numeric input with native validation and composable step controls.

Installation

pnpm dlx @mielui/svelte add number-field

Usage

NumberField keeps one native number input as the form control. Put name, form, min, max, step, required, disabled, and readonly on Root, and bind value to a number. Clearing the input sets it to undefined.

Native validation reports missing values, bounds, and step mismatches; typing never clamps a value silently. The arrow keys and the step buttons follow the browser's step rules and stop at the bounds, and an invalid step falls back to 1. The wheel is left alone. Format read-only totals with Intl.NumberFormat; the field does not format currency.

Label and Input share an id; set inputId on Root to choose it. If you set id on Input yourself, also set for on Label, or name the input with Field.Control. Pass descriptions and errors to Input. With a SvelteKit remote form, put the field name on Root, pass the current number as value, and update it in onValueChange.

<script lang="ts">
    import * as NumberField from '@mielui/svelte/components/number-field';

    let seats = $state<number | undefined>(2);
</script>

<NumberField.Root bind:value={seats} min={1} max={12}>
    <NumberField.Label>Seats</NumberField.Label>
    <NumberField.Group>
        <NumberField.Decrement />
        <NumberField.Input />
        <NumberField.Increment />
    </NumberField.Group>
</NumberField.Root>

Examples

Decimal steps

A step of 0.25 with both buttons after the input. Each stepper takes its own aria-label.

Form submission and reset

Disabled

Parts

Root renders its children, so you choose the order of the input and the two buttons, and the input keeps working when a button is left out. Root, Input, Decrement, and Increment take bind:element, for example to focus the input after a reset. Decrement and Increment take onclick, which runs before the value steps; call preventDefault() there to cancel the step.

Labels

Pass labels to Root to translate the accessible names of the two step buttons. Every key of NumberFieldLabels is optional; omitted keys keep the English text. An aria-label on a button wins.

<script lang="ts">
    import * as NumberField from '@mielui/svelte/components/number-field';
    import type { NumberFieldLabels } from '@mielui/svelte/components/number-field';

    const labels: NumberFieldLabels = {
        decrease: 'Diminuer',
        increase: 'Augmenter'
    };
</script>

<NumberField.Root {labels}>
    <NumberField.Label>Places</NumberField.Label>
    <NumberField.Group>
        <NumberField.Decrement />
        <NumberField.Input />
        <NumberField.Increment />
    </NumberField.Group>
</NumberField.Root>

API reference

NumberField.Root

  • labels
    NumberFieldLabels

    Overrides the built-in text and accessible names. Every key is optional and English is the fallback.

  • value Bindable
    number

    Current number. Bindable.

  • inputId
    string

    Id of the input, for a label outside the field.

  • min
    number

    Smallest allowed value.

  • max
    number

    Largest allowed value.

  • step
    number

    Amount each step changes the value by.

    Default 1

  • name
    string

    Field name submitted with the form.

  • form
    string

    Id of the form this control belongs to when it sits outside that form.

  • disabled
    boolean

    Prevents interaction and dims the control.

    Default false

  • readonly
    boolean

    Shows the value without allowing edits. The value is still submitted.

    Default false

  • required
    boolean

    Requires a value before the form can be submitted.

    Default false

  • onValueChange
    ((value: number | undefined) => void)

    Called with the new value when it changes.

  • children
    Snippet<[{ value: number | undefined; }]>

    Content rendered inside.

  • element Bindable
    HTMLDivElement

    Bindable reference to the DOM element.

NumberField.Decrement

  • onclick
    ((event: MouseEvent) => void)

    Called on click, before the value steps. Call preventDefault() to skip the step.

  • element Bindable
    HTMLButtonElement

    Bindable reference to the DOM element.

NumberField.Increment

  • onclick
    ((event: MouseEvent) => void)

    Called on click, before the value steps. Call preventDefault() to skip the step.

  • element Bindable
    HTMLButtonElement

    Bindable reference to the DOM element.

NumberField.Input

  • element Bindable
    HTMLInputElement

    Bindable reference to the DOM element.

Other parts

These parts have no props of their own. They pass HTML attributes and events to their element.

  • NumberField.Group
  • NumberField.Label