← All UI specs

Component contract

input

Native <input> wrapped as a design-system custom element — supports text/email/password/search/tel/url/number types, invalid+describedBy for error states, and emits dsInput with the current value on every keystroke.

Version
v1.0.0

Props

NameTypeValuesDefault
valuestring
namestring
typeenumtext, email, password, search, tel, url, numbertext
placeholderstring
disabledbooleanfalse
requiredbooleanfalse
invalidbooleanfalse
describedBystring
labelstring
sizeenummd, lgmd

Events

NamePayloadCondition
dsInputstring

Tokens

spacing
sm, md, lg, xl
radius
sm, md
font
family, size-md

Accessibility

native_element
input
labeling
aria-label via the label prop (canonical) or ambient <label> wrapper (secondary, browser-computed accessible name).
keyboard
["Tab focuses","Printable characters insert at caret","Backspace/Delete edit natively","Arrow keys move caret (Up/Down step numeric value when type=number)","Enter may submit the enclosing form for type=search"]
disabled_semantics
native_disabled_attribute
error_semantics
aria-invalid (from `invalid` prop) + aria-describedby (from `describedBy` prop, expected to point at a light-DOM node id containing the error message)
required_semantics
aria-required (from `required` prop); visual asterisk is the consumer's responsibility
notes
label prop is REQUIRED for WCAG conformance — an <input> with no accessible name is an axe `label` violation. `placeholder` is a hint, not a label — always pair with `label`. `autocomplete` is intentionally not exposed in v1; consumers that need password-manager hints for password fields can render a native <input> for that field until the prop is added.
Raw validated JSON
{
  "name": "input",
  "version": "1.0.0",
  "props": {
    "value": {
      "type": "string"
    },
    "name": {
      "type": "string"
    },
    "type": {
      "type": "enum",
      "values": [
        "text",
        "email",
        "password",
        "search",
        "tel",
        "url",
        "number"
      ],
      "default": "text"
    },
    "placeholder": {
      "type": "string"
    },
    "disabled": {
      "type": "boolean",
      "default": false
    },
    "required": {
      "type": "boolean",
      "default": false
    },
    "invalid": {
      "type": "boolean",
      "default": false
    },
    "describedBy": {
      "type": "string"
    },
    "label": {
      "type": "string"
    },
    "size": {
      "type": "enum",
      "values": [
        "md",
        "lg"
      ],
      "default": "md"
    }
  },
  "events": {
    "dsInput": {
      "payload": "string"
    }
  },
  "tokens_used": {
    "spacing": [
      "sm",
      "md",
      "lg",
      "xl"
    ],
    "radius": [
      "sm",
      "md"
    ],
    "font": [
      "family",
      "size-md"
    ]
  },
  "a11y": {
    "native_element": "input",
    "labeling": "aria-label via the label prop (canonical) or ambient <label> wrapper (secondary, browser-computed accessible name).",
    "keyboard": [
      "Tab focuses",
      "Printable characters insert at caret",
      "Backspace/Delete edit natively",
      "Arrow keys move caret (Up/Down step numeric value when type=number)",
      "Enter may submit the enclosing form for type=search"
    ],
    "disabled_semantics": "native_disabled_attribute",
    "error_semantics": "aria-invalid (from `invalid` prop) + aria-describedby (from `describedBy` prop, expected to point at a light-DOM node id containing the error message)",
    "required_semantics": "aria-required (from `required` prop); visual asterisk is the consumer's responsibility",
    "notes": "label prop is REQUIRED for WCAG conformance — an <input> with no accessible name is an axe `label` violation. `placeholder` is a hint, not a label — always pair with `label`. `autocomplete` is intentionally not exposed in v1; consumers that need password-manager hints for password fields can render a native <input> for that field until the prop is added."
  }
}