<!-- 04_VISUAL/xwui/xwui-lib/xwui-lib-super/src/forms/XWUIChoiceGroup/XWUIChoiceGroup.md -->
# XWUIChoiceGroup

A selection group whose options render as cards, tiles, chips, rows or avatars, with radio, switch or toggle
semantics. Options carry an identity hue (a token NAME), a description, meta lines, a trailing pill, a corner tag, a
leading visual (icon, avatar, badge, host-drawn glyph, preview strip), a progress line and the states disabled, proposed,
dimmed, fits, warn and danger. The avatar variant is the board toolbar person filter: dim the others, a "+N" overflow menu.
It composes basic `XWUIAvatar`, `XWUITag` and `XWUIProgressBar` through their pure `projectView`, fills icon slots with
`XWUIIcon`, and hangs `XWUIMenuDropdown` on the overflow trigger. Spec: plnx `REF_06_GAPS.md` C04.

## Basic Usage

```example
file: examples/BasicUsage.ts
html: examples/BasicUsage.html
title: Basic Usage
description: Sign-up doors: four radio cards with a corner tag and an identity hue; the group is required and submits as door.
```

```example
file: examples/PersonFilter.ts
html: examples/PersonFilter.html
title: Board toolbar person filter
description: Avatars as a nullable radio: a second press clears, the others dim, past five people a +N menu lists the rest.
```

```example
file: examples/NeedChips.ts
html: examples/NeedChips.html
title: Need chips with a tier tag
description: Toggle chips for a pricing estimator, each with the first tier that includes it; Clear empties the set.
```

```example
file: examples/SourceSwitches.ts
html: examples/SourceSwitches.html
title: Data-source switches
description: Switch rows for what an assistant may read; a warn tone on personal data; at least one stays on.
```

## Data

| Field | Type | Meaning |
| --- | --- | --- |
| `options[]` | `XWUIChoiceOption` | The options, in order (see below). |
| `value` | `string \| string[] \| null` | Radio: an id or null. Switch and toggle: ids. Host-owned (v-model). |
| `status` | `'ready' \| 'loading' \| 'error'` | Inline state: skeleton placeholders with `aria-busy`, or an alert. |
| `message` | `string` | Error text for `status: 'error'`. |

`XWUIChoiceOption`: `id`, `title` (model text, never HTML), `description?`, `meta?: string[]`, `pill?: { label, tone?, hue? }`,
`corner?`, `hue?` (a NAME: `violet` resolves to `var(--xwui-hue-violet, var(--xwui-hue-slate))`), `icon?` (XWUIIcon name),
`visual?: 'icon' | 'avatar' | 'glyph' | 'badge' | 'preview'` (inferred when unset), `person?: { name, initials?, src? }`,
`badge?`, `glyph?` (an `h()` drawing), `preview?` (an `h()` drawing or bars `{ start, size, hue? }` as fractions),
`progress?` (0..100), `state?: 'done' | 'current' | 'running'`, `tone?: 'default' | 'warn' | 'danger'`, `disabled?`,
`proposed?`, `dimmed?`, `fit?`, `lang?`, `dir?`. Ids starting with `__` are reserved; repeats keep the first.

Host drawings are data, so they pass a sanitiser: drawing tags only (`svg`, `g`, `path`, `rect`, `circle`, `ellipse`, `line`,
`polyline`, `polygon`, `text`, `tspan`, `title`, `span`), no `html`, events, refs, props, `on*`, `href`, `src` or `url()`.

## Options

| Option | Default | What it does |
| --- | --- | --- |
| `mode` | `'radio'` | `radio` one value; `switch` many, one `role=switch` each; `toggle` many, `aria-pressed` buttons. |
| `variant` | `'card'` | `card`, `tile`, `chip`, `row`, `avatar`. Semantics never depend on it. |
| `columns` | `'auto'` | Most columns for card and tile (1..12); the grid drops columns below `minItemWidth`. |
| `minItemWidth` | card `14rem`, tile `9rem` | A plain CSS length or `var(--token)`; anything else is ignored. |
| `size` | `'md'` | `'sm'` tightens padding and text. |
| `ariaLabel`, `labelledBy` | | Names the group; `labelledBy` (a heading id) wins. |
| `nullable` | `false` | Radio: a second press clears (the person filter). |
| `minSelected` | `0` | Switch and toggle: the fewest that stay on. |
| `max` | | Avatar: how many show before "+N" (a "+1" never appears; that option shows instead). |
| `dimOthers` | `false` | Fade the options that are not selected while something is. |
| `showClear` | `false` | A Clear button while clearing is allowed. |
| `mirrorVisual` | `false` | Flip the glyph visual in RTL. |
| `flow` | avatar `scroll`, chip `wrap` | Chip and avatar rows wrap, or scroll inline inside a toolbar. |
| `selectOnFocus` | `true` | Radio: arrows also select (WAI-ARIA). Off for a filter, where every pick refetches. |
| `disabled`, `readonly`, `required` | `false` | `required` + `checkValidity()` drive `aria-invalid` and the message. |
| `name` | | Form field: one hidden input per value. |
| `labels` | locale pack | `clear`, `more` (`{n}`), `selected`, `fits`, `person` (`{name}`), `empty`, `loading`, `error`, `required`. |
| `skeletonCount` | `3` | Placeholders while loading. |
| `locale`, `numberingSystem` | page, `'latn'` | Badge numbers, percent and "+N"; Western digits unless asked. |

## Events and methods

- `onChange({ value, source, id })`: the user changed the value (`source` `'pointer'` or `'keyboard'`; `id` null for Clear).
  The logic event is `valueChange` (the base `change` event already means "state changed"); the container also
  dispatches DOM `input` then `change` (`CustomEvent`, `detail` as above), so `<xwui-choice-group>` works with listeners and v-model.
- `getValue()`, `setValue(value)` (silent host sync), `press(id)`, `clear()`, `checkValidity()`, `setDisabled(flag)`,
  `updateData(patch)`, `updateConfig(patch)`, `getElement()`, `destroy()`.
- Custom element: form associated. `getValidityAnchor()` (the `required` input) mirrors validity onto the host;
  `formReset()` restores the first value; a disabled `<fieldset>` disables the group.

## Accessibility and RTL

- radio: `radiogroup` (`aria-required`, `aria-readonly`, `aria-invalid`) of `role=radio` options; switch: `group` of
  `role=switch`; toggle: `group` of `role=button` with `aria-pressed`. One roving tab stop: Down and Right go forward, Up
  and Left back, mirrored in RTL (forward is Left there); Home and End jump; disabled options are skipped; Enter and Space
  press. The "+N" trigger is the last stop, a real button with `aria-haspopup="menu"` and `aria-expanded`.
- Each option is named by its title (`aria-labelledby`) and described by its description, meta, progress, pill, corner,
  fit badge and state or tone words (`aria-describedby`). Avatar options are named from `labels.person` ("Reem's items").
- Selection is never colour alone: a radio dot, a check, a switch thumb or an avatar ring and check badge. Warn and danger
  carry a thick inline-start bar and a spoken word; done, current and running carry a check, a ring, a pulse and a word.
- Targets: cards at least 44 px tall, chips 32 px (44 px on coarse pointers), avatars 32 px with a grown hit area.
- Logical properties only; direction comes from the parent `dir`; options may carry their own `lang` and `dir`.
- Motion: the hover lift, transitions and the running pulse stop under `prefers-reduced-motion`, read in CSS and in JS
  (the adapter follows the media query and adds `.xwui-choice-group-still`).

```api
```
