---
title: "Number"
description: "Collect a finite number with optional minimum/maximum bounds and optional display formatting."
group: "Build forms"
order: 4
type: "reference"
parent: "fields"
keywords:
  - "number"
  - "min"
  - "max"
  - "validation"
  - "decimals"
  - "prefix"
  - "suffix"
  - "grouped"
  - "notation"
  - "separators"
updated: "2026-07-20"
---

The number field collects a finite numeric value and stores it as a number. Decimals, a prefix, a suffix, and thousand separators (browser-detected or author-fixed) are optional — they only change how the answer is DISPLAYED.

## Options

| Option | Type | Default | Behavior |
| --- | --- | --- | --- |
| `min` | `number` | none | Rejects a smaller value |
| `max` | `number` | none | Rejects a larger value |
| `decimals` | `number` | none | Rounds the DISPLAYED value only (0–6) — the stored value is untouched, unlike `calculated` |
| `prefix` | `string` | none | Display-only text before the value, e.g. `$` |
| `suffix` | `string` | none | Display-only text after the value, e.g. ` kg` |
| `notation` | `"grouped"` \| `"grouped-comma"` \| `"grouped-dot"` | none | Thousand separators in the SDK input while it's unfocused: `"grouped"` detects the browser locale, `"grouped-comma"` is always `1,234.56`, `"grouped-dot"` is always `1.234,56` |
| `required` | `boolean` | `false` | Requires a finite number |

String values from a raw client are normalized to numbers before validation. `Infinity`, hexadecimal input, and non-numeric text are rejected.

For identifiers — postal codes, invoice numbers, anything with significant leading zeroes — use a text field instead. A number field stores `007` as `7`.

## Add a number field

In the dashboard, select **Add block**, choose **Number**, and set either bound when the range is part of the question. Decimals, prefix, suffix, and thousand separators sit alongside.

```ts
const seatsField = {
  id: "seats",
  kind: "number",
  label: "How many seats do you need?",
  min: 1,
  max: 500,
  required: true,
} as const;
```

## Formatting is display-only

`decimals`, `prefix`, and `suffix` change how the answer is shown, never what's stored:

```ts
const budgetField = {
  id: "budget",
  kind: "number",
  label: "Project budget",
  prefix: "$",
  decimals: 2,
  notation: "grouped",
} as const;
```

This is a deliberate divergence from the [calculated](/docs/fields/calculated) field, whose `decimals` rounds the stored value itself. A number field is the respondent's own input — silently rewriting `6.999` to `7` on submit would be data loss, so validation and the stored value are untouched; `formatAnswer` may show `7.00` for a stored `6.999`. A suffix keeps its edge spacing, so `suffix: " kg"` renders "3 kg", not "3kg".

Formatting shows up in the SDK's input adornments, the responses grid, CSV exports, notification emails, and Zapier's `formatted` answer map. The raw number is preserved everywhere else: the stored value, response `data` and `answers` payloads, Google Sheets numeric cells (kept native so `SUM`/`AVERAGE` still work), Notion number properties, and piping — `{{budget}}` inserts the plain number `1234.5`, not `$1,234.50`, same as a calculated field.

## Thousand separators

`notation` takes one of three values, named by the group separator:

- `"grouped"` — detect from the respondent's browser locale: `1,234.56` in the US, `1.234,56` in Germany. This is the default meaning of turning separators on.
- `"grouped-comma"` — always comma groups with a dot decimal, `1,234.56`, regardless of the respondent's locale.
- `"grouped-dot"` — always dot groups with a comma decimal, `1.234,56`, regardless of the respondent's locale.

Fix the style when your audience spans locales and the form copy already commits to one convention — a Danish price list showing `1.234,56 kr` shouldn't regroup as `1,234.56 kr` for a visitor whose browser is set to English. The parser is symmetric about respondent habits either way: a separator run that isn't exact 3-digit grouping reads as a decimal mark, so `12,5` typed into a comma-grouping input means `12.5`, never a silently stripped `125`.

Separators appear while the input is unfocused. Typing shows the raw text as typed, and the value sent to your server is always canonical: group separators stripped, the decimal mark normalized to `.`. Nothing grouped ever reaches `data`, drafts, piping, conditions, or the POST body — a raw API client posting `"1,234"` still gets rejected exactly as before.

An SDK older than the version that added this feature simply renders a plain, unformatted number input instead of the grouped one — a working fallback, not broken behavior — so `decimals`, `prefix`, `suffix`, and `notation` do not raise the form's minimum SDK version the way a calculated field does.

## Related

- [Calculated](/docs/fields/calculated): Show a derived, server-recomputed number with the same decimals/prefix/suffix formatting, but decimals rounds the stored value.
- [Linear scale](/docs/fields/linear-scale): Offer a fixed set of numbered choices.
- [Short text](/docs/fields/short-text): Preserve leading zeroes in an identifier.
- [Logic](/docs/logic): Compare numeric answers with `gt` and `lt` conditions.
- [Styling](/docs/styling): Style the `.fillo-number` prefix/suffix wrapper.
