# Input

A controlled text input, paired with Field for a persistent label and useful validation.

Version: 0.2.0-preview.1 (preview)
Content digest: 70ac710f4d22dce040e7ac593379ba8aca9dcb59a0b9c0f839819cae0e2bb721
Contract kind: curated
Source: packages/design-system/src/components/primitives/Input/Input.tsx

## Guidance

{
  "summary": "A controlled text input, paired with Field for a persistent label and useful validation.",
  "when_to_use": [
    "Collect a single-line value.",
    "Choose the native input type for the value being collected.",
    "Place one Input inside each Field."
  ],
  "avoid": [
    "Using placeholder text as the only label.",
    "Rendering a controlled input without onChange unless readOnly or disabled.",
    "Showing a red ring without explanatory text."
  ],
  "accessibility": [
    "Field connects the visible label and helper or error text to the input.",
    "Use autoComplete and inputMode when applicable.",
    "Keyboard focus surrounds the complete control."
  ],
  "constraints": [
    "value is required; onChange receives the edited string.",
    "Use surface=raised directly on a page canvas.",
    "The return key advances within a form or data-cds-form-scope unless callback behavior is selected."
  ]
}

## Contract and public API

```json
{
  "props": [
    {
      "name": "id",
      "type": "string",
      "required": false,
      "description": "DOM id the control renders, which the Field's label points at."
    },
    {
      "name": "disabled",
      "type": "boolean",
      "required": false,
      "description": "Blocks editing and focus, and dims the field. Prefer `readOnly` to keep it focusable."
    },
    {
      "name": "required",
      "type": "boolean",
      "required": false,
      "description": "Marks the control required for native form semantics."
    },
    {
      "name": "invalid",
      "type": "boolean",
      "required": false,
      "description": "Paints the invalid treatment and announces the control as invalid. A Field supplies\nthis from its own `error`; set it directly only for a control with no Field around it."
    },
    {
      "name": "ariaDescribedBy",
      "type": "string",
      "required": false,
      "description": "Ids of the helper or error copy describing the control, supplied by a parent Field."
    },
    {
      "name": "ariaLabelledBy",
      "type": "string",
      "required": false,
      "description": "Id of the visible label naming the control, supplied by a parent Field."
    },
    {
      "name": "value",
      "type": "string",
      "required": true,
      "description": "Current field value (controlled)."
    },
    {
      "name": "onChange",
      "type": "(value: string) => void",
      "required": false,
      "description": "Called with the next value on each edit."
    },
    {
      "name": "onEnter",
      "type": "() => void",
      "required": false,
      "description": "Called when Enter is pressed while focused."
    },
    {
      "name": "enterBehavior",
      "type": "InputEnterBehavior",
      "required": false,
      "description": "Return-key behavior. `advance` moves focus to the next compatible form\ncontrol before falling back to `onEnter`."
    },
    {
      "name": "enterKeyHint",
      "type": "InputEnterKeyHint",
      "required": false,
      "description": "Native on-screen keyboard return key hint."
    },
    {
      "name": "placeholder",
      "type": "string",
      "required": false,
      "description": "Placeholder text. Falls back to a wording keyed off `type`; `text` and `date` have none."
    },
    {
      "name": "size",
      "type": "InputSize",
      "required": false,
      "description": "Field size. Defaults to `md` for backwards-compatible form density."
    },
    {
      "name": "type",
      "type": "InputType",
      "required": false,
      "description": "Native input type, which also picks the default placeholder. `search` additionally defaults\n`enterBehavior` to `callback`, so its return key submits instead of moving focus."
    },
    {
      "name": "surface",
      "type": "InputSurface",
      "required": false,
      "description": "Container background treatment; use `raised` on cream canvases."
    },
    {
      "name": "ariaLabel",
      "type": "string",
      "required": false,
      "description": "Accessible name when no visible label is associated with the field."
    },
    {
      "name": "ariaControls",
      "type": "string",
      "required": false,
      "description": "ID of an associated popup/list controlled by this input."
    },
    {
      "name": "inputMode",
      "type": "React.InputHTMLAttributes<HTMLInputElement>['inputMode']",
      "required": false,
      "description": "On-screen keyboard hint (e.g. `numeric` for SSN/phone fields)."
    },
    {
      "name": "maxLength",
      "type": "number",
      "required": false,
      "description": "Native character-count limit on typed input."
    },
    {
      "name": "autoComplete",
      "type": "string",
      "required": false,
      "description": "Native autocomplete hint."
    },
    {
      "name": "autoCorrect",
      "type": "'on' | 'off'",
      "required": false,
      "description": "Native autocorrect hint."
    },
    {
      "name": "autoCapitalize",
      "type": "'off' | 'none' | 'on' | 'sentences' | 'words' | 'characters'",
      "required": false,
      "description": "Native autocapitalize hint."
    },
    {
      "name": "spellCheck",
      "type": "boolean",
      "required": false,
      "description": "Native spellcheck hint."
    },
    {
      "name": "name",
      "type": "string",
      "required": false,
      "description": "Form field name."
    },
    {
      "name": "readOnly",
      "type": "boolean",
      "required": false,
      "description": "Prevents editing while preserving focus and form submission semantics."
    },
    {
      "name": "min",
      "type": "React.InputHTMLAttributes<HTMLInputElement>['min']",
      "required": false,
      "description": "Native minimum value constraint."
    },
    {
      "name": "max",
      "type": "React.InputHTMLAttributes<HTMLInputElement>['max']",
      "required": false,
      "description": "Native maximum value constraint."
    },
    {
      "name": "step",
      "type": "React.InputHTMLAttributes<HTMLInputElement>['step']",
      "required": false,
      "description": "Native numeric step constraint."
    },
    {
      "name": "pattern",
      "type": "string",
      "required": false,
      "description": "Native validation pattern."
    },
    {
      "name": "leading",
      "type": "React.ReactNode",
      "required": false,
      "description": "Optional leading content inside the field shell."
    },
    {
      "name": "trailing",
      "type": "React.ReactNode",
      "required": false,
      "description": "Optional trailing content inside the field shell."
    },
    {
      "name": "trailingAction",
      "type": "React.ReactNode",
      "required": false,
      "description": "Optional trailing action inside the field shell."
    },
    {
      "name": "onFocus",
      "type": "() => void",
      "required": false,
      "description": "Called when the field gains focus."
    },
    {
      "name": "onBlur",
      "type": "() => void",
      "required": false,
      "description": "Called on blur, before any return-key advance moves focus on to the next control."
    },
    {
      "name": "className",
      "type": "string",
      "required": false,
      "description": "Class hook for the field wrapper."
    },
    {
      "name": "style",
      "type": "React.CSSProperties",
      "required": false,
      "description": "Inline style override for the field wrapper."
    },
    {
      "name": "testId",
      "type": "string",
      "required": false,
      "description": "Optional test selector. Lands on the `<input>`."
    }
  ],
  "prop_shapes": {},
  "api": {
    "method": "typescript-type-checker",
    "typescript_version": "5.9.3",
    "public_export": "Input",
    "public_path": "Input",
    "import_path": "@cloakedinc/design-system",
    "root_kind": "component",
    "entrypoints": [
      {
        "name": "Input",
        "signature": 1,
        "visibility": "public",
        "source": {
          "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
          "line": 112
        },
        "props_type": "InputProps",
        "props": [
          {
            "name": "value",
            "type": "string",
            "declared_type": "string",
            "required": true,
            "description": "Current field value (controlled).",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 36
            }
          },
          {
            "name": "onChange",
            "type": "((value: string) => void) | undefined",
            "declared_type": "(value: string) => void",
            "required": false,
            "description": "Called with the next value on each edit.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 38
            }
          },
          {
            "name": "onEnter",
            "type": "(() => void) | undefined",
            "declared_type": "() => void",
            "required": false,
            "description": "Called when Enter is pressed while focused.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 40
            }
          },
          {
            "name": "enterBehavior",
            "type": "InputEnterBehavior | undefined",
            "declared_type": "InputEnterBehavior",
            "required": false,
            "description": "Return-key behavior. `advance` moves focus to the next compatible form\ncontrol before falling back to `onEnter`.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 45
            },
            "values": [
              "advance",
              "callback"
            ],
            "values_complete": true
          },
          {
            "name": "enterKeyHint",
            "type": "InputEnterKeyHint | undefined",
            "declared_type": "InputEnterKeyHint",
            "required": false,
            "description": "Native on-screen keyboard return key hint.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 47
            },
            "values": [
              "done",
              "enter",
              "go",
              "next",
              "previous",
              "search",
              "send"
            ],
            "values_complete": true
          },
          {
            "name": "placeholder",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "Placeholder text. Falls back to a wording keyed off `type`; `text` and `date` have none.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 49
            }
          },
          {
            "name": "size",
            "type": "InputSize | undefined",
            "declared_type": "InputSize",
            "required": false,
            "description": "Field size. Defaults to `md` for backwards-compatible form density.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 51
            },
            "values": [
              "md",
              "sm"
            ],
            "values_complete": true,
            "default": "'md'",
            "default_kind": "source-expression"
          },
          {
            "name": "type",
            "type": "InputType | undefined",
            "declared_type": "InputType",
            "required": false,
            "description": "Native input type, which also picks the default placeholder. `search` additionally defaults\n`enterBehavior` to `callback`, so its return key submits instead of moving focus.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 56
            },
            "values": [
              "date",
              "email",
              "number",
              "password",
              "search",
              "tel",
              "text",
              "url"
            ],
            "values_complete": true,
            "default": "'text'",
            "default_kind": "source-expression"
          },
          {
            "name": "surface",
            "type": "InputSurface | undefined",
            "declared_type": "InputSurface",
            "required": false,
            "description": "Container background treatment; use `raised` on cream canvases.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 58
            },
            "values": [
              "default",
              "raised"
            ],
            "values_complete": true,
            "default": "'default'",
            "default_kind": "source-expression"
          },
          {
            "name": "disabled",
            "type": "boolean | undefined",
            "declared_type": "boolean",
            "required": false,
            "description": "Blocks editing and focus, and dims the field. Prefer `readOnly` to keep it focusable.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 60
            },
            "values": [
              false,
              true
            ],
            "values_complete": true
          },
          {
            "name": "ariaLabel",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "Accessible name when no visible label is associated with the field.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 62
            }
          },
          {
            "name": "ariaControls",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "ID of an associated popup/list controlled by this input.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 64
            }
          },
          {
            "name": "inputMode",
            "type": "\"search\" | \"email\" | \"none\" | \"text\" | \"tel\" | \"url\" | \"numeric\" | \"decimal\" | undefined",
            "declared_type": "React.InputHTMLAttributes<HTMLInputElement>['inputMode']",
            "required": false,
            "description": "On-screen keyboard hint (e.g. `numeric` for SSN/phone fields).",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 66
            },
            "values": [
              "decimal",
              "email",
              "none",
              "numeric",
              "search",
              "tel",
              "text",
              "url"
            ],
            "values_complete": true
          },
          {
            "name": "maxLength",
            "type": "number | undefined",
            "declared_type": "number",
            "required": false,
            "description": "Native character-count limit on typed input.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 68
            }
          },
          {
            "name": "autoComplete",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "Native autocomplete hint.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 70
            }
          },
          {
            "name": "autoCorrect",
            "type": "\"on\" | \"off\" | undefined",
            "declared_type": "'on' | 'off'",
            "required": false,
            "description": "Native autocorrect hint.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 72
            },
            "values": [
              "off",
              "on"
            ],
            "values_complete": true
          },
          {
            "name": "autoCapitalize",
            "type": "\"none\" | \"on\" | \"off\" | \"sentences\" | \"words\" | \"characters\" | undefined",
            "declared_type": "'off' | 'none' | 'on' | 'sentences' | 'words' | 'characters'",
            "required": false,
            "description": "Native autocapitalize hint.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 74
            },
            "values": [
              "characters",
              "none",
              "off",
              "on",
              "sentences",
              "words"
            ],
            "values_complete": true
          },
          {
            "name": "spellCheck",
            "type": "boolean | undefined",
            "declared_type": "boolean",
            "required": false,
            "description": "Native spellcheck hint.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 76
            },
            "values": [
              false,
              true
            ],
            "values_complete": true
          },
          {
            "name": "name",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "Form field name.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 78
            }
          },
          {
            "name": "readOnly",
            "type": "boolean | undefined",
            "declared_type": "boolean",
            "required": false,
            "description": "Prevents editing while preserving focus and form submission semantics.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 80
            },
            "values": [
              false,
              true
            ],
            "values_complete": true
          },
          {
            "name": "min",
            "type": "string | number | undefined",
            "declared_type": "React.InputHTMLAttributes<HTMLInputElement>['min']",
            "required": false,
            "description": "Native minimum value constraint.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 82
            }
          },
          {
            "name": "max",
            "type": "string | number | undefined",
            "declared_type": "React.InputHTMLAttributes<HTMLInputElement>['max']",
            "required": false,
            "description": "Native maximum value constraint.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 84
            }
          },
          {
            "name": "step",
            "type": "string | number | undefined",
            "declared_type": "React.InputHTMLAttributes<HTMLInputElement>['step']",
            "required": false,
            "description": "Native numeric step constraint.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 86
            }
          },
          {
            "name": "pattern",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "Native validation pattern.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 88
            }
          },
          {
            "name": "leading",
            "type": "React.ReactNode",
            "declared_type": "React.ReactNode",
            "required": false,
            "description": "Optional leading content inside the field shell.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 90
            }
          },
          {
            "name": "trailing",
            "type": "React.ReactNode",
            "declared_type": "React.ReactNode",
            "required": false,
            "description": "Optional trailing content inside the field shell.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 92
            }
          },
          {
            "name": "trailingAction",
            "type": "React.ReactNode",
            "declared_type": "React.ReactNode",
            "required": false,
            "description": "Optional trailing action inside the field shell.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 94
            }
          },
          {
            "name": "onFocus",
            "type": "(() => void) | undefined",
            "declared_type": "() => void",
            "required": false,
            "description": "Called when the field gains focus.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 96
            }
          },
          {
            "name": "onBlur",
            "type": "(() => void) | undefined",
            "declared_type": "() => void",
            "required": false,
            "description": "Called on blur, before any return-key advance moves focus on to the next control.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 98
            }
          },
          {
            "name": "className",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "Class hook for the field wrapper.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 100
            }
          },
          {
            "name": "style",
            "type": "React.CSSProperties | undefined",
            "declared_type": "React.CSSProperties",
            "required": false,
            "description": "Inline style override for the field wrapper.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 102
            }
          },
          {
            "name": "testId",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "Optional test selector. Lands on the `<input>`.",
            "source": {
              "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
              "line": 104
            }
          },
          {
            "name": "id",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "DOM id the control renders, which the Field's label points at.",
            "source": {
              "path": "packages/design-system/src/hooks/FieldContext.ts",
              "line": 22
            }
          },
          {
            "name": "required",
            "type": "boolean | undefined",
            "declared_type": "boolean",
            "required": false,
            "description": "Marks the control required for native form semantics.",
            "source": {
              "path": "packages/design-system/src/hooks/FieldContext.ts",
              "line": 26
            },
            "values": [
              false,
              true
            ],
            "values_complete": true
          },
          {
            "name": "invalid",
            "type": "boolean | undefined",
            "declared_type": "boolean",
            "required": false,
            "description": "Paints the invalid treatment and announces the control as invalid. A Field supplies\nthis from its own `error`; set it directly only for a control with no Field around it.",
            "source": {
              "path": "packages/design-system/src/hooks/FieldContext.ts",
              "line": 31
            },
            "values": [
              false,
              true
            ],
            "values_complete": true
          },
          {
            "name": "ariaDescribedBy",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "Ids of the helper or error copy describing the control, supplied by a parent Field.",
            "source": {
              "path": "packages/design-system/src/hooks/FieldContext.ts",
              "line": 33
            }
          },
          {
            "name": "ariaLabelledBy",
            "type": "string | undefined",
            "declared_type": "string",
            "required": false,
            "description": "Id of the visible label naming the control, supplied by a parent Field.",
            "source": {
              "path": "packages/design-system/src/hooks/FieldContext.ts",
              "line": 35
            }
          }
        ],
        "branches": [],
        "constraints": [],
        "extraction_status": "extracted"
      }
    ],
    "type_sources": [
      {
        "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
        "line": 7,
        "name": "InputType",
        "code": "export type InputType = 'text' | 'password' | 'email' | 'tel' | 'url' | 'search' | 'number' | 'date';"
      },
      {
        "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
        "line": 8,
        "name": "InputSize",
        "code": "export type InputSize = 'sm' | 'md';"
      },
      {
        "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
        "line": 9,
        "name": "InputEnterBehavior",
        "code": "export type InputEnterBehavior = 'advance' | 'callback';"
      },
      {
        "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
        "line": 10,
        "name": "InputEnterKeyHint",
        "code": "export type InputEnterKeyHint = 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send';"
      },
      {
        "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
        "line": 28,
        "name": "InputSurface",
        "code": "export type InputSurface = 'default' | 'raised';"
      },
      {
        "path": "packages/design-system/src/components/primitives/Input/Input.tsx",
        "line": 34,
        "name": "InputProps",
        "code": "export interface InputProps extends FieldControlProps {\n    /** Current field value (controlled). */\n    value: string;\n    /** Called with the next value on each edit. */\n    onChange?: (value: string) => void;\n    /** Called when Enter is pressed while focused. */\n    onEnter?: () => void;\n    /**\n     * Return-key behavior. `advance` moves focus to the next compatible form\n     * control before falling back to `onEnter`.\n     */\n    enterBehavior?: InputEnterBehavior;\n    /** Native on-screen keyboard return key hint. */\n    enterKeyHint?: InputEnterKeyHint;\n    /** Placeholder text. Falls back to a wording keyed off `type`; `text` and `date` have none. */\n    placeholder?: string;\n    /** Field size. Defaults to `md` for backwards-compatible form density. */\n    size?: InputSize;\n    /**\n     * Native input type, which also picks the default placeholder. `search` additionally defaults\n     * `enterBehavior` to `callback`, so its return key submits instead of moving focus.\n     */\n    type?: InputType;\n    /** Container background treatment; use `raised` on cream canvases. */\n    surface?: InputSurface;\n    /** Blocks editing and focus, and dims the field. Prefer `readOnly` to keep it focusable. */\n    disabled?: boolean;\n    /** Accessible name when no visible label is associated with the field. */\n    ariaLabel?: string;\n    /** ID of an associated popup/list controlled by this input. */\n    ariaControls?: string;\n    /** On-screen keyboard hint (e.g. `numeric` for SSN/phone fields). */\n    inputMode?: React.InputHTMLAttributes<HTMLInputElement>['inputMode'];\n    /** Native character-count limit on typed input. */\n    maxLength?: number;\n    /** Native autocomplete hint. */\n    autoComplete?: string;\n    /** Native autocorrect hint. */\n    autoCorrect?: 'on' | 'off';\n    /** Native autocapitalize hint. */\n    autoCapitalize?: 'off' | 'none' | 'on' | 'sentences' | 'words' | 'characters';\n    /** Native spellcheck hint. */\n    spellCheck?: boolean;\n    /** Form field name. */\n    name?: string;\n    /** Prevents editing while preserving focus and form submission semantics. */\n    readOnly?: boolean;\n    /** Native minimum value constraint. */\n    min?: React.InputHTMLAttributes<HTMLInputElement>['min'];\n    /** Native maximum value constraint. */\n    max?: React.InputHTMLAttributes<HTMLInputElement>['max'];\n    /** Native numeric step constraint. */\n    step?: React.InputHTMLAttributes<HTMLInputElement>['step'];\n    /** Native validation pattern. */\n    pattern?: string;\n    /** Optional leading content inside the field shell. */\n    leading?: React.ReactNode;\n    /** Optional trailing content inside the field shell. */\n    trailing?: React.ReactNode;\n    /** Optional trailing action inside the field shell. */\n    trailingAction?: React.ReactNode;\n    /** Called when the field gains focus. */\n    onFocus?: () => void;\n    /** Called on blur, before any return-key advance moves focus on to the next control. */\n    onBlur?: () => void;\n    /** Class hook for the field wrapper. */\n    className?: string;\n    /** Inline style override for the field wrapper. */\n    style?: React.CSSProperties;\n    /** Optional test selector. Lands on the `<input>`. */\n    testId?: string;\n}"
      },
      {
        "path": "packages/design-system/src/hooks/FieldContext.ts",
        "line": 20,
        "name": "FieldControlProps",
        "code": "export interface FieldControlProps {\n    /** DOM id the control renders, which the Field's label points at. */\n    id?: string;\n    /** Blocks interaction and dims the control. */\n    disabled?: boolean;\n    /** Marks the control required for native form semantics. */\n    required?: boolean;\n    /**\n     * Paints the invalid treatment and announces the control as invalid. A Field supplies\n     * this from its own `error`; set it directly only for a control with no Field around it.\n     */\n    invalid?: boolean;\n    /** Ids of the helper or error copy describing the control, supplied by a parent Field. */\n    ariaDescribedBy?: string;\n    /** Id of the visible label naming the control, supplied by a parent Field. */\n    ariaLabelledBy?: string;\n}"
      }
    ],
    "defaults_policy": "Only explicit destructured parameter initializers are extracted. Other runtime defaults remain in implementation source."
  },
  "spec": {
    "$schema": "../../../specs/component-spec.schema.json",
    "identity": {
      "name": "Input",
      "status": "preview",
      "version": "2.0.0",
      "summary": "A controlled single-line text field with native keyboard types, compact and standard sizes, slots, invalid state, and mobile return-key behavior. It renders no label or message of its own."
    },
    "parts": [
      {
        "id": "wrapper",
        "label": "Wrapper",
        "description": "Carries the caller's class and style around the control."
      },
      {
        "id": "control",
        "label": "Control",
        "description": "Owns the pill surface, selected size, invalid ring, and optional slots."
      },
      {
        "id": "field",
        "label": "Field",
        "description": "Provides native single-line input, keyboard, validation, and form semantics."
      },
      {
        "id": "leading",
        "label": "Leading slot",
        "description": "Holds a non-expanding icon or prefix before the field."
      },
      {
        "id": "trailing",
        "label": "Trailing slot",
        "description": "Holds a non-expanding suffix after the field."
      },
      {
        "id": "trailing-action",
        "label": "Trailing action",
        "description": "Holds a compact interactive action such as clear or show password."
      }
    ],
    "allowedDesignChoices": {
      "variants": {
        "base": {
          "label": "Base",
          "description": "The field has one pill-shaped control treatment."
        }
      },
      "sizes": {
        "sm": {
          "label": "Small"
        },
        "md": {
          "label": "Medium"
        }
      },
      "types": {
        "text": {
          "label": "Text",
          "description": "General single-line content with no more specific native input type."
        },
        "password": {
          "label": "Password",
          "description": "Masks a secret value and requests password input behavior."
        },
        "email": {
          "label": "Email",
          "description": "Requests an email keyboard and native email validation."
        },
        "tel": {
          "label": "Telephone",
          "description": "Requests a telephone keyboard for phone values."
        },
        "url": {
          "label": "URL",
          "description": "Requests a URL keyboard and native URL validation."
        },
        "search": {
          "label": "Search",
          "description": "Provides native search semantics for a bare search field."
        },
        "number": {
          "label": "Number",
          "description": "Supports native numeric minimum, maximum, and step constraints."
        },
        "date": {
          "label": "Date",
          "description": "Requests the native date picker; the value is an ISO YYYY-MM-DD string and the placeholder is platform-owned."
        }
      },
      "surfaces": {
        "default": {
          "label": "Default",
          "description": "Uses the input-container role on a raised host surface."
        },
        "raised": {
          "label": "Raised",
          "description": "Uses the raised surface role when the field sits directly on the page canvas."
        }
      }
    },
    "variants": [
      {
        "id": "base",
        "label": "Base",
        "description": "One pill-shaped field treatment configured through the separate type, surface, and size axes.",
        "platforms": [
          "ios",
          "android",
          "web"
        ]
      }
    ],
    "sizes": [
      {
        "id": "sm",
        "label": "Small",
        "description": "40-unit compact field for dense contexts."
      },
      {
        "id": "md",
        "label": "Medium",
        "description": "56-unit standard form field."
      }
    ],
    "measurements": [
      {
        "id": "small-height",
        "label": "Small control height",
        "kind": "exact",
        "token": "--cds-size-40",
        "value": 40,
        "unit": "px",
        "appliesTo": [
          "control",
          "sm"
        ]
      },
      {
        "id": "medium-height",
        "label": "Medium control height",
        "kind": "exact",
        "token": "--cds-size-56",
        "value": 56,
        "unit": "px",
        "appliesTo": [
          "control",
          "md"
        ]
      },
      {
        "id": "slot-gap",
        "label": "Slot gap",
        "kind": "exact",
        "token": "--cds-space-8",
        "value": 8,
        "unit": "px",
        "appliesTo": [
          "leading",
          "field",
          "trailing",
          "trailing-action"
        ]
      }
    ],
    "layout": {
      "alignment": "Field text and slots align on the control center line.",
      "flow": "Leading slot, flexible field, trailing slot, and trailing action form one row.",
      "notes": [
        "Wrap Input in Field for a visible label, helper text, or any validation copy; Field is the only owner of error messages.",
        "The control fills its parent width."
      ]
    },
    "typographyAndColor": {
      "typography": [
        {
          "label": "Medium field text",
          "description": "Standard fields use the body ramp.",
          "token": "--cds-type-body-size"
        },
        {
          "label": "Small field text",
          "description": "Compact fields use the body-small ramp outside the web anti-zoom floor.",
          "token": "--cds-type-body-small-size"
        }
      ],
      "colors": [
        {
          "label": "Default container",
          "description": "Uses the theme-aware input surface.",
          "token": "--cds-input-container"
        },
        {
          "label": "Raised container",
          "description": "Uses the raised surface role on a page canvas.",
          "token": "--cds-bg-surface"
        },
        {
          "label": "Field text",
          "description": "Uses primary text emphasis.",
          "token": "--cds-text-primary"
        },
        {
          "label": "Placeholder and slots",
          "description": "Use secondary text emphasis.",
          "token": "--cds-text-secondary"
        },
        {
          "label": "Invalid",
          "description": "Use the readable semantic danger role for error indication in both themes.",
          "token": "--cds-text-danger"
        }
      ]
    },
    "states": [
      {
        "id": "empty",
        "label": "Empty",
        "description": "Shows the explicit or type-specific placeholder."
      },
      {
        "id": "focused",
        "label": "Focused",
        "description": "Accepts input and shows a caret; there is no focus ring, since the design system targets a touch surface and the keyboard/caret already signal focus."
      },
      {
        "id": "filled",
        "label": "Filled",
        "description": "Shows the controlled value in primary text."
      },
      {
        "id": "invalid",
        "label": "Invalid",
        "description": "Shows the danger ring and invalid semantics; the control renders no message of its own. An enclosing Field supplies the corrective copy, and a standalone caller renders it elsewhere, such as a form-level summary."
      },
      {
        "id": "disabled",
        "label": "Disabled",
        "description": "Blocks editing and dims the whole control."
      },
      {
        "id": "read-only",
        "label": "Read only",
        "description": "Preserves focus and form semantics while preventing edits."
      }
    ],
    "behavior": [
      {
        "label": "Controlled editing",
        "description": "Request the next string on every edit while the parent owns the rendered value."
      },
      {
        "label": "Return-key behavior",
        "description": "Support advance to the next compatible field or invoke a callback; search and explicit callbacks default to callback behavior."
      },
      {
        "label": "Return-key labels",
        "description": "Support enter, done, go, next, previous, search, and send keyboard hints."
      },
      {
        "label": "Native types",
        "description": "Preserve text, password, email, telephone, URL, search, number, and date input semantics."
      }
    ],
    "accessibility": [
      {
        "label": "Accessible name",
        "description": "Associate a visible Field label or provide an accessible label when the input stands alone."
      },
      {
        "label": "Error relationship",
        "description": "Report invalid state on the control itself and render no message. An enclosing Field associates its rendered message with the control; a standalone caller associates the copy it renders elsewhere."
      },
      {
        "label": "Trailing actions",
        "description": "Give every interactive trailing action its own accessible name and stable test identifier."
      }
    ],
    "contentAdaptation": [
      {
        "label": "Placeholders",
        "description": "Use placeholders as examples or hints, never as the only persistent visible label for complex forms."
      },
      {
        "label": "Long values",
        "description": "Let the native single-line field scroll horizontally; use Textarea for multiline content."
      }
    ],
    "motionHaptics": {
      "motion": [
        {
          "label": "Focus and validation",
          "description": "Change borders and rings without moving the control."
        }
      ],
      "haptics": [
        {
          "label": "No intrinsic feedback",
          "description": "Typing and focus do not request design-system haptics; a trailing action owns its own feedback."
        }
      ]
    },
    "platformDifferences": [
      {
        "platforms": [
          "web"
        ],
        "description": "Small field text is floored at the 16px body size in the webview instead of rendering the 14px body-small size.",
        "rationale": "WKWebView zooms focused inputs below 16px; the font floor prevents an unexpected viewport jump while retaining the compact 40px shell."
      }
    ]
  },
  "platforms": {
    "implemented": [
      "web"
    ],
    "native": "Imported design guidance only; no native implementation or parity verification in this preview.",
    "react": {
      "implementation": "local",
      "status": "preview",
      "parity": "web-reference"
    },
    "vue": {
      "implementation": "absent",
      "parity": "not-verified",
      "status": "reference-only"
    },
    "swift": {
      "implementation": "absent",
      "parity": "not-verified",
      "status": "reference-only"
    },
    "kotlin": {
      "implementation": "absent",
      "parity": "not-verified",
      "status": "reference-only"
    }
  },
  "tokens": [
    {
      "name": "--cds-size-40",
      "light": "40px",
      "dark": "40px"
    },
    {
      "name": "--cds-size-56",
      "light": "56px",
      "dark": "56px"
    },
    {
      "name": "--cds-space-8",
      "light": "8px",
      "dark": "8px"
    },
    {
      "name": "--cds-type-body-size",
      "light": "1rem",
      "dark": "1rem"
    },
    {
      "name": "--cds-type-body-small-size",
      "light": "0.875rem",
      "dark": "0.875rem"
    },
    {
      "name": "--cds-input-container",
      "light": "#f3f1ed",
      "dark": "#232321"
    },
    {
      "name": "--cds-bg-surface",
      "light": "#ffffff",
      "dark": "#1b1b18"
    },
    {
      "name": "--cds-text-primary",
      "light": "#141410",
      "dark": "#f3f1ed"
    },
    {
      "name": "--cds-text-secondary",
      "light": "#646260",
      "dark": "#ffffff99"
    },
    {
      "name": "--cds-text-danger",
      "light": "#b83100",
      "dark": "color-mix(in srgb, #b83100 60%, #ffffff)"
    }
  ],
  "review": {
    "local_status": "not-reviewed",
    "source_approval": null,
    "imported_spec_status": "approved",
    "spec_origin": "imported-adapted",
    "local_spec_source_status": "preview",
    "imported_source_revision": "f96f416e1c3bfbfaffcd155a88b87b18b8bb25f1",
    "note": "Inherited specification status is provenance, not approval of the current local implementation or extracted contract."
  },
  "missing_facts": [
    {
      "code": "human-review-pending",
      "detail": "This local preview has no recorded human design or engineering sign-off."
    },
    {
      "code": "platform-parity-unverified",
      "detail": "Vue, Swift and Kotlin implementations are absent from this package; platform parity has not been verified."
    },
    {
      "code": "figma-mapping-unverified",
      "detail": "No current component-level Figma node and immutable revision have been verified for this contract."
    }
  ]
}
```

## Visual states

- [Playground](/storybook/iframe.html?id=cloaked-design-system-primitives-input--playground&viewMode=story) | export: Playground | source: packages/design-system/src/components/primitives/Input/Input.stories.tsx

- [State Matrix](/storybook/iframe.html?id=cloaked-design-system-primitives-input--state-matrix&viewMode=story) | export: StateMatrix | source: packages/design-system/src/components/primitives/Input/Input.stories.tsx

- [Focused](/storybook/iframe.html?id=cloaked-design-system-primitives-input--focused&viewMode=story) | export: Focused | source: packages/design-system/src/components/primitives/Input/Input.stories.tsx

- [Types](/storybook/iframe.html?id=cloaked-design-system-primitives-input--types&viewMode=story) | export: Types | source: packages/design-system/src/components/primitives/Input/Input.stories.tsx

- [With Slots](/storybook/iframe.html?id=cloaked-design-system-primitives-input--with-slots&viewMode=story) | export: WithSlots | source: packages/design-system/src/components/primitives/Input/Input.stories.tsx

- [Invalid In Field](/storybook/iframe.html?id=cloaked-design-system-primitives-input--invalid-in-field&viewMode=story) | export: InvalidInField | source: packages/design-system/src/components/primitives/Input/Input.stories.tsx

- [Raised On Canvas](/storybook/iframe.html?id=cloaked-design-system-primitives-input--raised-on-canvas&viewMode=story) | export: RaisedOnCanvas | source: packages/design-system/src/components/primitives/Input/Input.stories.tsx

- [Mobile Form Flow](/storybook/iframe.html?id=cloaked-design-system-primitives-input--mobile-form-flow&viewMode=story) | export: MobileFormFlow | source: packages/design-system/src/components/primitives/Input/Input.stories.tsx

- [Dark Theme](/storybook/iframe.html?id=cloaked-design-system-primitives-input--dark-theme&viewMode=story) | export: DarkTheme | source: packages/design-system/src/components/primitives/Input/Input.stories.tsx

## Field and Input playground

Source: packages/design-system/examples/InputPlayground.tsx

```tsx
import { useState } from 'react';
import { Field, Input } from '../src';
import { DemoFrame, SelectControl } from './DemoFrame';
import { inputExampleCode, type InputExampleProps } from './code';

export function InputPlayground() {
  const [email, setEmail] = useState('');
  const [size, setSize] = useState<InputExampleProps['size']>('md');
  const [state, setState] = useState<InputExampleProps['state']>('default');
  const error = state === 'invalid' ? 'Enter an email address, such as name@example.com.' : undefined;
  return <DemoFrame code={inputExampleCode({ size, state })} controls={<>
    <SelectControl label="Size" value={size} options={['md', 'sm']} onChange={value => setSize(value as InputExampleProps['size'])} />
    <SelectControl label="State" value={state} options={['default', 'invalid', 'disabled']} onChange={value => setState(value as InputExampleProps['state'])} />
  </>}>
    <div className="demo-input-stage">
      <Field label="Email address" helperText="Use the address you check regularly." error={error} disabled={state === 'disabled'}>
        <Input type="email" size={size} value={email} onChange={setEmail} autoComplete="email" />
      </Field>
    </div>
  </DemoFrame>;
}
```

## Create a protected email

Source: packages/design-system/examples/ProtectedEmailFlow.tsx

```tsx
import { useEffect, useLayoutEffect, useRef, useState, type FormEvent } from 'react';
import { Button, Field, Input } from '../src';
import { DemoFrame } from './DemoFrame';
import { createSampleIdentity, validateIdentity, type IdentityDraft, type IdentityErrors } from './protected-email';

const EMPTY_DRAFT: IdentityDraft = { name: '', website: '' };

export function ProtectedEmailFlow() {
  const [draft, setDraft] = useState<IdentityDraft>(EMPTY_DRAFT);
  const [errors, setErrors] = useState<IdentityErrors>({});
  const [stage, setStage] = useState<'editing' | 'loading' | 'success'>('editing');
  const form = useRef<HTMLFormElement>(null);
  const success = useRef<HTMLHeadingElement>(null);
  useEffect(() => {
    if (stage !== 'loading') return;
    const timer = window.setTimeout(() => setStage('success'), 700);
    return () => window.clearTimeout(timer);
  }, [stage]);
  useEffect(() => { if (stage === 'success') success.current?.focus(); }, [stage]);
  useLayoutEffect(() => {
    if (Object.keys(errors).length) form.current?.querySelector<HTMLInputElement>('[aria-invalid="true"]')?.focus();
  }, [errors]);
  const restart = () => {
    setDraft(EMPTY_DRAFT); setErrors({}); setStage('editing');
    requestAnimationFrame(() => form.current?.querySelector<HTMLInputElement>('input')?.focus());
  };
  const submit = (event: FormEvent) => {
    event.preventDefault();
    if (stage !== 'editing') return;
    const nextErrors = validateIdentity(draft);
    setErrors(nextErrors);
    if (Object.keys(nextErrors).length) return;
    setStage('loading');
  };
  return <DemoFrame><section className="demo-flow" aria-label="Create a protected email example">
    <p className="demo-sample-note">Interactive example · Sample data only. Nothing is sent or saved.</p>
    {stage === 'success' ? <FlowSuccess draft={draft} headingRef={success} restart={restart} /> :
      <form ref={form} noValidate onSubmit={submit} aria-busy={stage === 'loading'}>
        <FlowHeading />
        <FlowFields draft={draft} errors={errors} loading={stage === 'loading'} change={setDraft} submit={() => form.current?.requestSubmit()} />
        <Button variant="primary" size="md" fullWidth loading={stage === 'loading'} onPress={() => form.current?.requestSubmit()}>Create protected email</Button>
        <p className="demo-feedback" role="status">{stage === 'loading' ? 'Creating your sample address…' : 'Your personal email stays yours.'}</p>
      </form>}
  </section></DemoFrame>;
}

function FlowHeading() {
  return <div className="demo-flow-heading">
    <span className="demo-symbol" aria-hidden="true">@</span>
    <span className="demo-eyebrow">A little more privacy</span>
    <h2>An email for this part of your life.</h2>
    <p>Give it a name so you know where you used it.</p>
  </div>;
}

function FlowFields({ draft, errors, loading, change, submit }: {
  draft: IdentityDraft; errors: IdentityErrors; loading: boolean;
  change: (draft: IdentityDraft) => void; submit: () => void;
}) {
  return <div className="demo-flow-fields">
    <Field label="Name" helperText="For example, shopping or a newsletter." error={errors.name} required disabled={loading}>
      <Input value={draft.name} onChange={name => change({ ...draft, name })} placeholder="Shopping"
        name="identity-name" autoComplete="off" maxLength={80} enterKeyHint="next" />
    </Field>
    <Field label="Website (optional)" helperText="A reminder of where you'll use this address." error={errors.website} disabled={loading}>
      <Input value={draft.website} onChange={website => change({ ...draft, website })} placeholder="example.com"
        name="identity-website" autoComplete="off" inputMode="url" autoCapitalize="none" maxLength={200}
        enterKeyHint="done" enterBehavior="callback" onEnter={submit} />
    </Field>
  </div>;
}

function FlowSuccess({ draft, headingRef, restart }: {
  draft: IdentityDraft; headingRef: React.RefObject<HTMLHeadingElement>; restart: () => void;
}) {
  const identity = createSampleIdentity(draft);
  return <div className="demo-flow-success">
    <span className="demo-symbol demo-symbol-success" aria-hidden="true">✓</span>
    <span className="demo-eyebrow">Ready to use</span>
    <h2 ref={headingRef} tabIndex={-1}>A fresh address for {identity.name}.</h2>
    <p>This sample address demonstrates the result. It cannot receive email.</p>
    <div className="demo-email-result"><span>Protected email</span><strong>{identity.email}</strong></div>
    <Button variant="secondary" size="md" fullWidth onPress={restart}>Try the flow again</Button>
  </div>;
}
```

## Surfaces

Source: packages/design-system/examples/foundations/FoundationSurfaces.tsx

```tsx
import { useState } from 'react';
import { Field, Input, Text } from '../../src';
import { FoundationFrame } from './FoundationShared';

export function FoundationSurfaces() {
  const [name, setName] = useState('Shopping');
  return <FoundationFrame code={`const page = { background: 'var(--cds-bg-page)', color: 'var(--cds-text-primary)' };\nconst card = { background: 'var(--cds-bg-surface)' };\nconst inverse = { background: 'var(--cds-bg-inverse)', color: 'var(--cds-text-inverse)' };`}>
    <div className="foundation-surface-page">
      <code>--cds-bg-page</code>
      <div className="foundation-surface-card">
        <code>--cds-bg-surface</code>
        <Text as="h2" variant="h3-serif">Give your address a home.</Text>
        <Field label="Address name" helperText="A useful label makes it easier to find later.">
          <Input value={name} onChange={setName} placeholder="Shopping" autoComplete="off" />
        </Field>
        <code>Input → --cds-input-container</code>
      </div>
    </div>
    <div className="foundation-surface-inverse" data-testid="surface-inverse" style={{ background: 'var(--cds-bg-inverse)', color: 'var(--cds-text-inverse)' }}>
      <div><span className="demo-eyebrow">A deliberate change of context</span><Text as="h2" variant="h3-serif">Private feels different.</Text></div>
      <code>--cds-bg-inverse + --cds-text-inverse</code>
    </div>
    <p className="foundation-caption">Page, card, and input surfaces adapt to the selected theme. An inverse surface stays dark and keeps its own light foreground in both themes.</p>
  </FoundationFrame>;
}
```

Preview pending human sign-off. Source-derived APIs and successful checks do not certify accessibility, native parity or approval.
