{
  "tag": "ed-number-input",
  "kind": "component",
  "summary": "Number inputs allow users to enter and edit numeric values with stepper buttons.",
  "status": "experimental",
  "level": "atom",
  "since": "1.0",
  "docs": "https://test-apps.eurodata.de/a/eurodata-ui/docs/components/number-input/",
  "usage": "https://test-apps.eurodata.de/a/eurodata-ui/docs/components/number-input/usage/",
  "playwright": "getByTestId('…').getByRole('spinbutton')",
  "dependencies": [
    "ed-icon"
  ],
  "use": [
    "A countable, steppable value with a clear default that users typically nudge up or down by a step or two — number of guests, copies, line items",
    "A value that must obey a fixed granularity — the steppers move on the grid of allowed values, and a value typed off-grid is reported as invalid rather than silently corrected",
    "A quantity or number of items that the user raises or lowers with the arrow buttons",
    "A small integer field such as the number of months or installments, with a minimum and maximum checked by the field"
  ],
  "notFor": [
    {
      "when": "Prices, salaries and other amounts of money",
      "instead": "a text [Input](https://test-apps.eurodata.de/a/eurodata-ui/docs/components/input) with `inputmode=\"decimal\"` and the unit in the end slot, the product validating and formatting the amount"
    },
    {
      "when": "Wide-variability whole numbers (an age, a year such as the birth year) or large ranges — reaching the target takes too many clicks",
      "instead": "[Input](https://test-apps.eurodata.de/a/eurodata-ui/docs/components/input) with the number type (spin buttons hidden)"
    },
    {
      "when": "Numbers that are really formatted identifiers — phone numbers, IBANs, postal codes, card numbers, order references",
      "instead": "a text [Input](https://test-apps.eurodata.de/a/eurodata-ui/docs/components/input)"
    },
    {
      "when": "Picking from a short list of preset amounts",
      "instead": "a [Select](https://test-apps.eurodata.de/a/eurodata-ui/docs/components/select) or [Radio Group](https://test-apps.eurodata.de/a/eurodata-ui/docs/components/radio-group)"
    },
    {
      "when": "Decimal numbers other than amounts of money",
      "instead": "an [Input](https://test-apps.eurodata.de/a/eurodata-ui/docs/components/input) of type number"
    }
  ],
  "rules": [
    {
      "id": "number-input/stepping-helps",
      "rule": "Reach for Number Input only when stepping genuinely helps — values that stay in a small range around a common default (roughly 1–100), like a quantity of items.",
      "why": "The steppers are this component's reason to exist."
    },
    {
      "id": "number-input/hint-states-constraints",
      "rule": "State the unit, the allowed range and the step size in the hint (for example \"Weight in kg, 10–100, in steps of 5\").",
      "check": "warning"
    },
    {
      "id": "number-input/value-prominence",
      "rule": "Let the value be visually more prominent than its label when the two are shown together."
    },
    {
      "id": "form-controls/visible-label",
      "rule": "In a form, give every control a persistent, visible label — short, descriptive and in plain language — and never placeholder text in its place. Outside a form the container decides whether the label shows; where it does not, `aria-label` gives the control its name.",
      "why": "Placeholder text disappears the moment the user types, leaving no reminder of what the field expected.",
      "check": "error"
    },
    {
      "id": "form-controls/required",
      "rule": "Set `required` on a mandatory control and explain the required-marking convention once per form. Never add your own required indicator — the label picks it up."
    },
    {
      "id": "form-controls/error-timing",
      "rule": "Never show a validation error before the user has interacted with the control — not on page load, not on focus alone, not while they are still typing. Don't add your own timing: the control shows its errors after the user has left it or changed its value, and on submit.",
      "check": "error"
    },
    {
      "id": "form-controls/message-never-silenced",
      "rule": "Keep a message on every error. Write your own where the built-in wording does not fit — it replaces the built-in one — but never set `error` to an empty string or hide the message part: the error styling alone says that something is wrong, not what.",
      "check": "error"
    },
    {
      "id": "form-controls/readonly-not-disabled",
      "rule": "Use `readonly` for a value the user can never change — a calculated total, an assigned id — and `disabled` only while it could become editable under some condition.",
      "why": "Disabled implies the value could be unlocked, and a disabled control submits nothing; a read-only one submits its value."
    },
    {
      "id": "form-controls/min-width",
      "rule": "Keep a field at least 8.75rem (140px) wide, even for short values such as postal codes — and comfortably wider for prose.",
      "why": "The value, the label and any icons stay legible.",
      "check": "error",
      "covered": true
    },
    {
      "id": "form-controls/default-density",
      "rule": "Keep `density` at its default, and the same for every control in one row or form. Choose `compact` or `spacious` only where the user asks for it or the space leaves no other way — a form with many fields is no reason — and then for the whole layout, never to fine-tune spacing case by case. Where a container decides the density of the controls inside it, its rules say so.",
      "why": "The default is the intended spacing for almost every screen.",
      "check": "warning"
    },
    {
      "id": "form-controls/ai-suggested",
      "rule": "Set `ai` on a control whose value the system pre-filled, so users can tell it apart from their own entries; the state clears once they touch it."
    }
  ],
  "api": {
    "attributes": [
      {
        "name": "title",
        "property": "title",
        "type": "string",
        "default": "''"
      },
      {
        "name": "value",
        "property": "defaultValue",
        "type": "string",
        "description": "The default value of the form control. Primarily used for resetting the form control."
      },
      {
        "name": "density",
        "property": "density",
        "type": "'compact' | 'default' | 'spacious'",
        "default": "'default'",
        "description": "Controls the component's spacing density without affecting font-size."
      },
      {
        "name": "pill",
        "property": "pill",
        "type": "boolean",
        "default": "false",
        "description": "Draws a pill-style input with rounded edges."
      },
      {
        "name": "label",
        "property": "label",
        "type": "string",
        "default": "''",
        "description": "The input's label. If you need to display HTML, use the `label` slot instead."
      },
      {
        "name": "aria-label",
        "property": "ariaLabel",
        "type": "null | string",
        "default": "null",
        "description": "The input's accessible name for when no visible label is set. Mirrored onto the internal\ninput, where the spinbutton role lives — an aria-label left on the host alone would sit on\na role-less element and be ignored by assistive tech."
      },
      {
        "name": "placeholder",
        "property": "placeholder",
        "type": "string",
        "default": "''",
        "description": "Placeholder text to show as a hint when the input is empty."
      },
      {
        "name": "readonly",
        "property": "readonly",
        "type": "boolean",
        "default": "false",
        "description": "Makes the input readonly."
      },
      {
        "name": "required",
        "property": "required",
        "type": "boolean",
        "default": "false",
        "description": "Makes the input a required field."
      },
      {
        "name": "min",
        "property": "min",
        "type": "number",
        "description": "The input's minimum value."
      },
      {
        "name": "max",
        "property": "max",
        "type": "number",
        "description": "The input's maximum value."
      },
      {
        "name": "step",
        "property": "step",
        "type": "number",
        "description": "The granularity the value must adhere to. Anything that cannot form a grid — `any`, zero,\nnegative, unparseable — falls back to `1`.\n\nA native input also takes `any`, which turns stepping off entirely. This control does not,\nbecause a numeric field without steps is `<ed-input type=\"number\">`: stepper buttons are the\nreason to reach for this element, and `stepUp()` throws `InvalidStateError` in a mode that has\nno step — so the buttons would be there and broken."
      },
      {
        "name": "without-steppers",
        "property": "withoutSteppers",
        "type": "boolean",
        "default": "false",
        "description": "Hides the increment/decrement stepper buttons."
      },
      {
        "name": "autocomplete",
        "property": "autocomplete",
        "type": "string",
        "description": "Specifies what permission the browser has to provide assistance in filling out form field values. Refer to\n[this page on MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete) for available values."
      },
      {
        "name": "autofocus",
        "property": "autofocus",
        "type": "boolean",
        "description": "Indicates that the input should receive focus on page load."
      },
      {
        "name": "enterkeyhint",
        "property": "enterkeyhint",
        "type": "'next' | 'previous' | 'search' | 'send' | 'done' | 'enter' | 'go'",
        "description": "Used to customize the label or icon of the Enter key on virtual keyboards."
      },
      {
        "name": "inputmode",
        "property": "inputmode",
        "type": "'numeric' | 'decimal'",
        "default": "'numeric'",
        "description": "Tells the browser what type of data will be entered by the user, allowing it to display the appropriate virtual\nkeyboard on supportive devices."
      },
      {
        "name": "with-label",
        "property": "withLabel",
        "type": "boolean",
        "default": "false",
        "description": "Only required for SSR. Set to `true` if you're slotting in a `label` element so the server-rendered markup includes the label before the component hydrates on the client."
      },
      {
        "name": "with-hint",
        "property": "withHint",
        "type": "boolean",
        "default": "false",
        "description": "Only required for SSR. Set to `true` if you're slotting in a `hint` element so the server-rendered markup includes the hint before the component hydrates on the client."
      },
      {
        "name": "error",
        "property": "error",
        "type": "null | string",
        "default": "null",
        "description": "Draws an error-style input with danger colored border and icon. Set to an empty string (or use the bare attribute `<ed-input error>`) to render error styling without a visible message; submission is still blocked with a localized fallback validation message. Set to a non-empty string to additionally display that message in the message area, above the hint, and use it as the validation message. Set to `null` (the default) or `undefined`, or remove the attribute, to clear the error."
      },
      {
        "name": "warning",
        "property": "warning",
        "type": "null | string",
        "default": "null",
        "description": "Draws a warning-style input with warning colored border and icon. Set to an empty string (or use the bare attribute `<ed-input warning>`) to render warning styling without a visible message. Set to a non-empty string to additionally display that message in the message area, above the hint. Warnings do not block form submission. Set to `null` (the default) or `undefined`, or remove the attribute, to clear the warning."
      },
      {
        "name": "ai",
        "property": "ai",
        "type": "boolean",
        "default": "false",
        "description": "Draws an ai-style input with AI colored border and icon. Suppressed visually once\n`hasInteracted` flips, but the property and attribute are preserved so the styling\nreturns after `formResetCallback` clears `hasInteracted`."
      },
      {
        "name": "hint",
        "property": "hint",
        "type": "string",
        "default": "''",
        "description": "The form control's hint text. If you need to display HTML, use the `hint` slot instead."
      },
      {
        "name": "name",
        "property": "name",
        "type": "null | string",
        "default": "null",
        "description": "The name of the input, submitted as a name/value pair with form data."
      },
      {
        "name": "disabled",
        "property": "disabled",
        "type": "boolean",
        "description": "Disables the form control. HTML treats a control as disabled when either its own `disabled` is\nset or an ancestor `<fieldset>` is disabled, so reading this reports the combined state while\nwriting it sets only this element's own. Keeping the two apart is what lets a fieldset be\nre-enabled without clearing a disabled state the consumer set in the meantime."
      },
      {
        "name": "dir",
        "property": "dir",
        "type": "string"
      },
      {
        "name": "lang",
        "property": "lang",
        "type": "string"
      }
    ],
    "properties": [
      {
        "name": "value",
        "type": "string",
        "description": "The current value of the input, submitted as a name/value pair with form data. Empty is `''`,\nas on a native number input — never `null`."
      },
      {
        "name": "valueAsNumber",
        "type": "number",
        "description": "The current value as a number, and `NaN` while the control holds no usable one. An empty field\nand a field whose text is not a number give the same answer, because value has already\nemptied the second one.\n\nWriting `NaN` empties the control, and writing an infinity throws a `TypeError` — both as HTML\nrequires of the native setter. Neither `min`, `max` nor `step` corrects what is written: an\nout-of-range number is kept and reported through `validity.rangeOverflow`, as on a native input."
      },
      {
        "name": "form",
        "type": "HTMLFormElement | null",
        "description": "By default, form controls are associated with the nearest containing `<form>` element. This attribute allows you\nto place the form control outside of a form and associate it with the form that has this `id`. The form must be in\nthe same document or shadow root for this to work."
      },
      {
        "name": "validationTarget",
        "type": "undefined | HTMLElement",
        "description": "Override this to change where constraint validation popups are anchored."
      }
    ],
    "methods": [
      {
        "name": "focus",
        "parameters": [
          {
            "name": "options",
            "type": "FocusOptions",
            "optional": true
          }
        ],
        "description": "Sets focus on the input."
      },
      {
        "name": "blur",
        "description": "Removes focus from the input."
      },
      {
        "name": "select",
        "description": "Selects all the text in the input."
      },
      {
        "name": "stepUp",
        "description": "Increments the value by the step amount."
      },
      {
        "name": "stepDown",
        "description": "Decrements the value by the step amount."
      },
      {
        "name": "setCustomValidity",
        "parameters": [
          {
            "name": "message",
            "type": "string"
          }
        ],
        "description": "Do not use this when creating a \"Validator\". This is intended for end users of components.\nWe track manually defined custom errors so we don't clear them on accident in our validators."
      },
      {
        "name": "resetValidity",
        "description": "Reset validity is a way of removing manual custom errors and native validation."
      },
      {
        "name": "getPropertyDescriptor",
        "static": true,
        "parameters": [
          {
            "name": "name",
            "type": "PropertyKey"
          },
          {
            "name": "key",
            "type": "string | symbol"
          },
          {
            "name": "options",
            "type": "PropertyDeclaration"
          }
        ],
        "returns": "PropertyDescriptor | undefined",
        "description": "Wraps the accessor of reflected properties so they always hold a valid value, as a native\nreflected IDL attribute does (`button.type = undefined` reads `submit`):\n\n- A property that declares `useDefault` takes the first value set on an element for its\n  default. That value is its field initializer's: the constructor has finished before markup,\n  a framework or any other code can set anything. Every later `null` or `undefined` means what\n  a dropped prop means on a native element — the attribute is removed: with the attribute\n  there, it is removed and Lit's `useDefault` restores the default without writing it; without\n  one, the property is set to the default. A value set and cleared again before the element\n  updates still writes the default once, from the pending reflection.\n- A Boolean is coerced with `Boolean()`, so `undefined` is `false`.\n\nLit's `useDefault` keeps the initial default out of the DOM. Setting the default explicitly\nwrites it, as `button.type = 'submit'` writes `type`."
      }
    ],
    "events": [
      {
        "name": "input",
        "react": "onInput",
        "type": "InputEvent",
        "description": "Emitted when the control receives input."
      },
      {
        "name": "change",
        "react": "onChange",
        "type": "Event",
        "description": "Emitted when an alteration to the control's value is committed by the user."
      },
      {
        "name": "blur",
        "react": "onBlur",
        "description": "Emitted when the control loses focus."
      },
      {
        "name": "beforeinput",
        "react": "onBeforeinput",
        "description": "Emitted from a stepper button before the value changes. Call `event.preventDefault()` to cancel the change."
      },
      {
        "name": "focus",
        "react": "onFocus",
        "description": "Emitted when the control gains focus."
      },
      {
        "name": "ed-invalid",
        "react": "onEdInvalid",
        "description": "Emitted when the form control has been checked for validity and its constraints aren't satisfied."
      }
    ],
    "slots": [
      {
        "name": "label",
        "description": "The input's label. Alternatively, you can use the `label` attribute."
      },
      {
        "name": "start",
        "description": "An element, such as `<ed-icon>`, placed at the start of the input control."
      },
      {
        "name": "end",
        "description": "An element, such as `<ed-icon>`, placed at the end of the input control (before steppers)."
      },
      {
        "name": "increment-icon",
        "description": "An icon to use in lieu of the default increment icon."
      },
      {
        "name": "decrement-icon",
        "description": "An icon to use in lieu of the default decrement icon."
      },
      {
        "name": "hint",
        "description": "Text that describes how to use the input. Alternatively, you can use the `hint` attribute."
      }
    ],
    "cssProperties": [
      {
        "name": "--ed-number-input-width",
        "description": "Sets a fixed width for the input field"
      }
    ],
    "parts": [
      {
        "name": "label",
        "description": "The label element."
      },
      {
        "name": "form-control-label",
        "description": "Alias for the label element."
      },
      {
        "name": "message",
        "description": "The state message: an error, a warning, or the AI note."
      },
      {
        "name": "hint",
        "description": "The hint element."
      },
      {
        "name": "base",
        "description": "The wrapper containing the input and steppers."
      },
      {
        "name": "input",
        "description": "The internal `<input>` control."
      },
      {
        "name": "start",
        "description": "The container that wraps the `start` slot."
      },
      {
        "name": "end",
        "description": "The container that wraps the `end` slot."
      },
      {
        "name": "stepper",
        "description": "Both stepper buttons (for shared styling)."
      },
      {
        "name": "stepper-increment",
        "description": "The increment (+) button on the end side."
      },
      {
        "name": "stepper-decrement",
        "description": "The decrement (-) button on the start side."
      }
    ],
    "states": [
      {
        "name": "blank",
        "description": "The input is empty."
      },
      {
        "name": "disabled",
        "description": "The control is disabled, by its own attribute or by an ancestor fieldset."
      },
      {
        "name": "required",
        "description": "The control is required."
      },
      {
        "name": "optional",
        "description": "The control is not required."
      },
      {
        "name": "invalid",
        "description": "The value fails constraint validation, whether or not the user has touched the control yet."
      },
      {
        "name": "valid",
        "description": "The value passes constraint validation."
      },
      {
        "name": "user-invalid",
        "description": "Invalid, and the user has interacted with the control. This is the one to style for an error: it behaves like the platform's `:user-invalid`, so an untouched field is not marked wrong before the user has had a chance to fill it in."
      },
      {
        "name": "user-valid",
        "description": "Valid, and the user has interacted with the control."
      },
      {
        "name": "dirty",
        "description": "The user has interacted with the control."
      },
      {
        "name": "error",
        "description": "The `error` property is set, or the control is `user-invalid`."
      },
      {
        "name": "warning",
        "description": "The `warning` property is set."
      },
      {
        "name": "ai",
        "description": "The `ai` property is set and the user has not interacted with the control yet."
      }
    ]
  },
  "import": "import '@eurodata/eurodata-ui/dist/components/number-input/number-input.js';",
  "react": {
    "component": "EdNumberInput",
    "import": "import EdNumberInput from '@eurodata/eurodata-ui/dist/react/number-input/index.js';"
  }
}
