{
  "id": "input-otp",
  "name": "InputOtp",
  "level": "molecule",
  "status": "stable",
  "purpose": "Takes a one-time code, one digit per box, pasted or typed.",
  "description": "**Purpose.** Single-purpose molecule for entering a one-time code as a row of single-character slots. Auto-advances on input, retreats on backspace, distributes paste across the row, and exposes a single concatenated value to the form layer. Mirrors the Input atom's visual contract so the two read as the same family.\n\n**When to use.**\n- Two-factor authentication and email/SMS verification flows.\n- Account-recovery codes and step-up authentication.\n- Any short, fixed-length code that benefits from per-character visual feedback.\n\n**When NOT to use.**\n- Variable-length codes or longer secrets — use `Input type=\"password\"`.\n- Free-text identifiers or coupons — use `Input` with `pattern`.\n- Reading existing codes back to the user as plain text — render with `Code`.\n\n**Composes with.**\n- `Field` + `Field.Label` + `Field.Description` + `Field.Error` — wrap the row to inherit the molecule's full ARIA wiring and visual rhythm.\n- `Button` for the resend / submit affordances that typically sit beneath the row.\n- `Card.tone=\"elevated\"` as the canonical container for a sign-in step.\n\n**Accessibility.**\n- `aria-label` is required on the row (e.g. \"One-time code\"). Each slot is auto-labelled `Code digit N of LENGTH` so screen-reader users always know where they are.\n- The control wires `aria-invalid` and `aria-required` on every slot from the row's props; `aria-describedby` propagates so a `Field.Error` anchors correctly.\n- The first slot uses `autoComplete=\"one-time-code\"` so iOS/Android surface the SMS code as a keyboard suggestion.\n- `inputMode` defaults to `numeric` (numeric soft keyboard); `pattern` defaults to `^\\d$` per slot. Override both for alphanumeric codes.\n- Backspace clears the focused slot in place; pressing it again retreats. Arrow keys, Home, End and paste behave per platform expectations.\n- `disabled` dims the whole row as a single block; the slots remain in the tab order only when the row is enabled.\n\n**Related patterns.**\n- `Patterns/Forms · FieldAnatomy` — wrap the row in a `Field` for the canonical Label · Control · Description / Error stack.\n- `Patterns/Forms · ValidationFlow` — error placement and tone.\n- `Patterns/Feedback · InlineFeedback` — error lives next to its cause.\n- `Patterns/Composition · AtomToMolecule` — InputOtp is a leaf molecule, not a primitive.\n- `Patterns/Decision Matrix · ComponentChoice` — pick `InputOtp` over `Input` when the input is a fixed-length code.",
  "role": "input",
  "import": "@rrios-forge/ui/molecules/input-otp",
  "exports": [
    "InputOtp",
    "INPUT_OTP_SIZES",
    "inputOtpSlotVariants",
    "inputOtpVariants"
  ],
  "source": "packages/ui/src/molecules/input-otp",
  "axes": [
    {
      "axis": "size",
      "part": null,
      "values": [
        "sm",
        "md",
        "lg"
      ],
      "default": "md",
      "meaning": "Ergonomic scale, in three families (control, text, container)."
    },
    {
      "axis": "invalid",
      "part": null,
      "values": [
        "true",
        "false"
      ],
      "default": "false",
      "meaning": "Fails validation: a danger edge, announced as invalid; pair it with an error message."
    },
    {
      "axis": "filled",
      "part": null,
      "values": [
        "true",
        "false"
      ],
      "default": "false",
      "meaning": "Holds a value: the label stays raised over the field."
    },
    {
      "axis": "disabled",
      "part": null,
      "values": [
        "true",
        "false"
      ],
      "default": "false",
      "meaning": "Not available: dimmed, skipped by the keyboard, ignores the pointer."
    }
  ],
  "needs": [
    {
      "need": "OTP / 2FA code",
      "answer": "`InputOtp` (molecule)"
    }
  ],
  "patterns": [
    "Patterns/Forms · FieldAnatomy",
    "Patterns/Forms · ValidationFlow",
    "Patterns/Feedback · InlineFeedback",
    "Patterns/Composition · AtomToMolecule",
    "Patterns/Decision Matrix · ComponentChoice"
  ],
  "a11yExceptions": [],
  "decisions": [],
  "stories": [
    {
      "name": "Playground",
      "id": "components-molecules-inputotp--playground",
      "interaction": false,
      "snapshots": [
        "dark",
        "light"
      ],
      "skipsSnapshot": false,
      "docs": "/?path=/story/components-molecules-inputotp--playground",
      "frame": "/iframe.html?id=components-molecules-inputotp--playground&viewMode=story"
    },
    {
      "name": "Sizes",
      "id": "components-molecules-inputotp--sizes",
      "interaction": false,
      "snapshots": [
        "dark",
        "light"
      ],
      "skipsSnapshot": false,
      "docs": "/?path=/story/components-molecules-inputotp--sizes",
      "frame": "/iframe.html?id=components-molecules-inputotp--sizes&viewMode=story"
    },
    {
      "name": "States",
      "id": "components-molecules-inputotp--states",
      "interaction": false,
      "snapshots": [
        "dark",
        "high-contrast",
        "light"
      ],
      "skipsSnapshot": false,
      "docs": "/?path=/story/components-molecules-inputotp--states",
      "frame": "/iframe.html?id=components-molecules-inputotp--states&viewMode=story"
    },
    {
      "name": "In Context",
      "id": "components-molecules-inputotp--in-context",
      "interaction": false,
      "snapshots": [
        "dark",
        "high-contrast",
        "light"
      ],
      "skipsSnapshot": false,
      "docs": "/?path=/story/components-molecules-inputotp--in-context",
      "frame": "/iframe.html?id=components-molecules-inputotp--in-context&viewMode=story"
    },
    {
      "name": "Typing flow (interaction test)",
      "id": "components-molecules-inputotp--typing-flow",
      "interaction": true,
      "snapshots": [],
      "skipsSnapshot": true,
      "docs": "/?path=/story/components-molecules-inputotp--typing-flow",
      "frame": "/iframe.html?id=components-molecules-inputotp--typing-flow&viewMode=story"
    }
  ],
  "storyFile": "tooling/storybook/stories/components/molecules/input-otp.stories.tsx"
}
