{
  "name": "SelectableTile",
  "source": "src/components/SelectableTile.tsx",
  "propsType": "SelectableTileProps",
  "description": "SelectableTile — a choice the size of a card: a plan, a schedule, a\ntemplate, with a sentence about each.\n\nA REAL CHECKBOX OR RADIO, THE SIZE OF A CARD. Inside a RadioGroup it is a\nRadio; inside a CheckboxGroup, or alone, a Checkbox — the same native input\nthose render, so the group's name, value, required rule, disabled state and\nerror wiring all apply, arrow keys move between radios, and a form submits\nit. The title is the input's label; its label is stretched over the tile,\nso the whole card is the target, not only the box.\n\nTHE NAME IS THE TITLE. The description and anything below it are read after\nthe name, through `aria-describedby`, rather than folded into it: \"Pro,\nradio button, 2 of 3, Unlimited agents and priority support\".\n\nNOTHING INSIDE IS INTERACTIVE. The whole tile is one control; a link in it\nwould be unreachable by pointer and confusing by keyboard. Put a \"Compare\nplans\" link beside the group.\n\nSELECTED IS MORE THAN A COLOUR. The tile's border thickens and takes the\nbrand colour, and the box or dot is filled — the same indicator as a plain\ncheckbox or radio, so the state survives greyscale and forced colours.",
  "import": "import { SelectableTile } from 'ionbase-ui';",
  "status": "stable",
  "summary": "A choice the size of a card — a plan, a schedule, a template, each with a sentence. A real Radio inside a RadioGroup, a real Checkbox inside a CheckboxGroup or alone; its label is stretched over the tile, so the whole card is the target. The title is the name; the description is read after it.",
  "useWhen": [
    "each option needs a sentence or a detail to be chosen well — what a plan includes, what a schedule costs",
    "there are a handful of options, two to six, worth seeing side by side"
  ],
  "useInstead": [
    {
      "when": "the options are short labels that need no explanation",
      "use": "RadioGroup",
      "why": "a column of radios is denser and quicker to scan than a grid of cards"
    },
    {
      "when": "more than about six options, or a list that grows",
      "use": "Select",
      "why": "a grid of tiles for twenty options is a wall of cards"
    },
    {
      "when": "the card leads somewhere, or holds actions",
      "use": "Card",
      "why": "a tile is one control and must hold nothing interactive"
    }
  ],
  "composition": {
    "order": [
      "RadioGroup",
      "SelectableTile"
    ],
    "note": "Inside a RadioGroup the tiles are radios — one choice; inside a CheckboxGroup, checkboxes — several. The group's label, description, isRequired, isInvalid and errorMessage apply as they do to Radio and Checkbox, and the tiles wrap into a grid. Alone, a tile is a checkbox with `isSelected` and `onSelectionChange`. Put links — \"Compare plans\" — beside the group, not in a tile.",
    "example": "<RadioGroup label=\"Plan\" value={plan} onChange={setPlan}><SelectableTile value=\"team\" title=\"Team\" description=\"Up to 20 agents.\">€49 a month</SelectableTile></RadioGroup>"
  },
  "a11y": {
    "requires": [
      "`title` — the option's name, short: it is the input's accessible name",
      "a group label on the RadioGroup or CheckboxGroup — the question the tiles answer"
    ],
    "guarantees": [
      "it is a native radio or checkbox: arrow keys move between radios, Space toggles a checkbox, and a form submits its value",
      "the whole tile is the target, through the input's own label",
      "the description and extra detail are read after the name, through aria-describedby",
      "the group's help or error is read on each tile, as on Radio and Checkbox",
      "selected thickens the border and fills the indicator — not a colour change alone",
      "a keyboard focus ring goes round the whole tile",
      "the icon is hidden from assistive tech"
    ],
    "notes": [
      "nothing inside a tile may be interactive — the whole tile is one control",
      "the tiles wrap into a grid 14rem and up, so a phone gets one column"
    ]
  },
  "antiPatterns": [
    {
      "dont": "<Card onClick={() => setPlan('team')} aria-pressed={plan === 'team'}>",
      "do": "<SelectableTile value=\"team\" title=\"Team\" />",
      "why": "a clickable card is not a radio: it is not grouped, arrow keys do nothing, and a form does not submit it"
    },
    {
      "dont": "a \"Learn more\" link inside a tile",
      "do": "the link beside the group",
      "why": "the whole tile is the control; a link on top of it is a second target in the same place"
    }
  ],
  "stylesheet": "src/styles/selectable-tile.css",
  "tokens": [
    "--border-default",
    "--border-disabled",
    "--border-error-strong",
    "--border-primary-strong",
    "--border-width-default",
    "--border-width-thick",
    "--font-family-sans",
    "--font-weight-semibold",
    "--icon-secondary",
    "--ion-duration-base",
    "--ion-ease-out",
    "--radius-lg",
    "--ring-focus",
    "--spacing-12",
    "--spacing-16",
    "--spacing-4",
    "--spacing-8",
    "--surface-default",
    "--surface-disabled",
    "--surface-hover",
    "--text-default",
    "--text-disabled",
    "--text-secondary",
    "--type-body-sm",
    "--type-body-sm-line-height"
  ],
  "props": {
    "value": {
      "type": "string",
      "required": true,
      "origin": "own",
      "description": "The option's value — what the group reports."
    },
    "title": {
      "type": "React.ReactNode",
      "required": true,
      "origin": "own",
      "description": "The option's name, and the tile's accessible name: \"Pro\", \"Weekly\"."
    },
    "description": {
      "type": "React.ReactNode",
      "required": false,
      "origin": "own",
      "description": "What choosing it means, in a sentence. Read after the name."
    },
    "icon": {
      "type": "React.ReactNode",
      "required": false,
      "origin": "own",
      "description": "A decorative mark above the title. Hidden from assistive tech."
    },
    "children": {
      "type": "React.ReactNode",
      "required": false,
      "origin": "own",
      "description": "More detail below the description — a price, a limit. Read with the\ndescription. Text only: nothing inside a tile may be interactive, since\nthe whole tile is its control."
    },
    "isDisabled": {
      "type": "boolean | undefined",
      "required": false,
      "origin": "own"
    },
    "isSelected": {
      "type": "boolean | undefined",
      "required": false,
      "origin": "own",
      "description": "Standalone only, outside a group: whether it is ticked."
    },
    "defaultSelected": {
      "type": "boolean | undefined",
      "required": false,
      "origin": "own",
      "description": "Standalone only: the starting state."
    },
    "onSelectionChange": {
      "type": "((isSelected: boolean) => void) | undefined",
      "required": false,
      "origin": "own",
      "description": "Standalone only: called with the new state."
    },
    "className": {
      "type": "string | undefined",
      "required": false,
      "origin": "own"
    }
  },
  "propCounts": {
    "own": 10,
    "aria": 0,
    "dom": 0,
    "other": 0
  }
}
