Number input

SvNumberInput on its own: min/max/step, thousands grouping, precision, prefix/suffix, spinner buttons and the shared field contract (label, hint, required/error validation).

A live, editable Svelte 5 component example from the SvGrid gallery (Inputs). Read the SvGrid UI component docs for the full API.

About this example

SvNumberInput on its own in Svelte 5: min, max and step bounds, thousands grouping, precision, prefix and suffix, spinner buttons and the shared field contract with a label, a hint and required or error validation. It is the SvGrid number cell editor, standalone.

SvNumberInput on its own - min/max/step, thousands grouping, precision, prefix/suffix, spinner buttons, plus the shared field contract (label, hint, required/error validation). The SvGrid number cell editor, standalone.

Imports, features and API used

Imports: @svgrid/grid

Frequently asked questions

How is the value kept within bounds?

min and max clamp typed and stepped values, and step sets the spinner and arrow-key increment. onChange receives a number, or null when the field is cleared.

How do I show a currency?

Set prefix='$' or a suffix such as 'kg', grouping for thousands separators and precision={2} for cents. The formatting is display only; the value stays a plain number.

How does validation surface?

required marks the field, and passing invalid with an error message shows the message under the input in the same way every field in the kit does.

Related documentation

Related articles

Source code (300-number-input.svelte)

<script lang="ts">
  /**
   * SvNumberInput on its own - min/max/step, thousands grouping, precision,
   * prefix/suffix, spinner buttons, plus the shared field contract (label, hint,
   * required/error validation). The SvGrid number cell editor, standalone.
   */
  import { SvNumberInput } from '@svgrid/grid'

  let qty = $state<number | null>(3)
  let price = $state<number | null>(1299.5)
  let pct = $state<number | null>(20)
  let budget = $state<number | null>(null)
  const budgetError = $derived(budget == null ? 'Enter a budget' : budget < 100 ? 'Minimum is 100' : undefined)
</script>

<div class="wrap">
  <header>
    <h2>Number input</h2>
    <p><code>SvNumberInput</code> - typed numeric entry with clamping, grouping, precision and spinners. Emits <code>number | null</code>.</p>
  </header>

  <div class="grid">
    <label class="cell">Quantity (0-99, step 1)
      <SvNumberInput value={qty} min={0} max={99} step={1} onChange={(v) => (qty = v)} />
      <span class="val">{qty}</span>
    </label>

    <label class="cell">Price (grouped, 2dp, prefix)
      <SvNumberInput value={price} min={0} precision={2} grouping prefix="$" step={0.5} selectOnFocus wheelStep onChange={(v) => (price = v)} />
      <span class="val">{price}</span>
    </label>

    <label class="cell">Percent (suffix, no spinners)
      <SvNumberInput value={pct} min={0} max={100} suffix="%" spinButtons={false} onChange={(v) => (pct = v)} />
      <span class="val">{pct}</span>
    </label>

    <div class="cell">
      <SvNumberInput
        value={budget}
        label="Monthly budget"
        hint="At least 100 - clearable"
        prefix="$"
        grouping
        clearable
        required
        invalid={!!budgetError}
        error={budgetError}
        onChange={(v) => (budget = v)}
      />
    </div>
  </div>
</div>

<style>
  .wrap { padding: 20px; max-width: 720px; display: flex; flex-direction: column; gap: 18px; }
  header h2 { margin: 0 0 4px; font-size: 20px; font-weight: 700; }
  header p { margin: 0; color: var(--sg-muted, #64748b); font-size: 13.5px; line-height: 1.5; }
  code { background: var(--sg-row-hover-bg, #eef2ff); padding: 1px 5px; border-radius: 5px; font-size: 12px; }
  .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 20px; align-items: start; }
  .cell { display: flex; flex-direction: column; gap: 6px; font-size: 12px; font-weight: 600; color: var(--sg-muted, #64748b); }
  .val { font-size: 12px; color: var(--sg-muted, #94a3b8); font-weight: 400; }
</style>

View this example on GitHub

More Inputs examples

  • Text inputs - Typed text controls: SvNumberInput (min/max/step, grouping, precision, spinners), SvPasswordInput (reveal + strength), SvMaskedInput (pattern mask), SvPhoneInput (country dial code + national mask) and SvColorInput (swatch + palette popover). Each a SvGrid cell editor, standalone too.
  • Input adornments - Leading/trailing icon snippets and prefix/suffix text affixes on SvTextInput, plus the shared clear button, sizes and invalid/readonly/disabled states - all owned by SvField's frame chrome so the whole text-input family behaves identically.
  • Password input - SvPasswordInput on its own: a reveal toggle and an optional 4-level strength meter, with localizable strings and the shared field contract.
  • Masked input - SvMaskedInput on its own: a fixed-pattern mask (# digit, A letter, * alphanumeric; other chars literal) emitting the masked + raw value and a complete flag.
  • Phone input - SvPhoneInput on its own: a country dial-code selector plus a national number field emitting an E.164-ish string, with label / validation / dir.