<!-- GENERATED by scripts/build-llms.mjs from llms/forms.md — do not edit this file. -->

# `lr-radio-group`

- **Import** `import '@aceshooting/lyra-ui/components/lr-radio-group.js';` (stable tag alias; registers the tag)
- **Compound usage registrations** `import '@aceshooting/lyra-ui/components/lr-radio.js';`, `import '@aceshooting/lyra-ui/components/lr-radio-button.js';` — required by the consumer-supplied child tags in this reference; usage-only, not registration dependencies of `lr-radio-group`
- **Class** `LyraRadioGroup`, also available unregistered from `@aceshooting/lyra-ui/components/forms/radio/radio-group.class.js`
- **Family** `components/forms/` — see `llms/index.md` for its siblings
- **Status** `stable` since `4.0.0` — see the maturity and deprecation policy in `llms/shared.md`
- **Release history** [CHANGELOG.md](../../CHANGELOG.md); family-wide breaking-change summaries: [llms-full.txt](../../llms-full.txt)
- **Deprecations** none
- **Optional peers** none
- **Themeable via** 11 parts, 4 custom properties — see this component's own `@csspart`/`@cssprop` list below
- **Library-wide behavior** (events, form association, `locale`/`strings`, tokens, TS types): `llms/shared.md`

---

## `lr-radio-group`

A labeled, keyboard-navigable group of `lr-radio` controls. Home/End and the orientation's arrow
axis move focus and select the next enabled radio: Up/Down when vertical, Left/Right when
horizontal. Horizontal direction mirrors under RTL, and disabled options are skipped.

Host `aria-describedby` references resolve onto the internal `role="radiogroup"` before its local
hint/error guidance. References track unresolved IDs, target replacement/removal/reinsertion,
reconnect, and document adoption. Group descriptions remain on the group; child radios can carry
their own separately authored descriptions.

**Properties:** `label`, `hint`, `helpText` (`help-text`, Shoelace alias), `errorText`
(`error-text`), `name` (empty by default, with the empty attribute omitted), live `value`, reflected
`defaultValue` (attribute `value`; Shoelace's `default-value` is also accepted), `customError`
(`custom-error`), `required`, `disabled`, `orientation: 'vertical' | 'horizontal' = 'vertical'`,
`withLabel`/`withHint` (`with-label`/`with-hint` SSR presence hints), `aria-label` (through
`accessibleLabel`; attribute presence wins, including `aria-label=""`, and suppresses the
visible-label `aria-labelledby` fallback), and `size: LyraSize = 'm'` (reflected) — the size of the
group's **own** chrome, on the shared ladder and accepting both `2xs`/`xs`/`s`/`m`/`l`/`xl` and
`small`/`medium`/`large`. It scales the group's label type size and the gaps around and between its
options off the same values the controls themselves use, and projects that tier to every owned
`<lr-radio>`/`<lr-radio-button>` child (including children added later). Group size and name are
authoritative through each option's `effectiveSize`/`effectiveName`, but never rewrite the child's
authored public properties or attributes; late child writes are restored immediately on removal or
reparenting.

When renaming `<sl-radio-group>` manually, set `name="option"` if the old markup relied on
Shoelace's implicit form-data key. Lyra deliberately defaults `name` to empty; the bundled migration
codemod inserts the compatibility value automatically.

The group is the sole aggregate form-associated owner. A non-empty selected value contributes one
`name=value` entry; owned radios suppress their own entries and validity while a standalone radio
continues to participate independently. `form`, `getForm()`, `labels`, native validity, external
form ownership, fieldset disablement, reset, and session restoration all live on the group.
`value` is non-reflecting live state; `defaultValue`/the `value` attribute is the current reset
default and cannot overwrite a dirty selection. Reset restores that current default, and session
restore selects the stored value silently even when it arrives before the radio children.
A required but pristine group keeps `aria-invalid="false"` on its internal radiogroup; the value
error is projected only after interaction or a native validity check (`checkValidity()`,
`reportValidity()`, or form-level validation), while explicit error chrome is immediate.

**Events:** per owned selection — including keyboard activation — the group emits, in order,
a bubbling/composed `InputEvent` named `input`, `lr-input`, a bubbling/composed `Event` named
`change`, then exactly one group-owned `lr-change`. The two native events carry no detail (read
`event.target.value`);
both prefixed aliases carry `{ value, radio }`. The selected child does not emit its standalone
value events. Ownership is resolved synchronously, so immediate removal restores standalone
behavior and immediate reparenting routes the event to the new group without waiting for a
mutation-observer turn. `lr-invalid` (no detail) is group-owned and fires when the group's validity
check fails; a consumer listening above the group does not receive a second prefixed alias from the
child validity owner.

**Slots:** default radios, `label`, `hint`, `help-text` (Shoelace hint alias), `error`.

**CSS parts:** `base`, `form-control`, `label` / `form-control-label`, `radios` /
`form-control-input` / `button-group` / `button-group__base`, `hint` /
`form-control-help-text`, and `error`.

**The required marker.** `required` with a non-empty group `label` paints the library's shared
marker on the `form-control-label` node — the one `::after` rule described under "The
required-field marker" above, not a copy of it, so `--lr-form-control-required-content`,
`--lr-form-control-required-color` and `--lr-form-control-required-offset` retune or suppress it
here exactly as they do on `lr-input`. It marks the **group**, not the individual radios: an owned
`<lr-radio>` has no label box of its own and paints nothing. With no group label text the node is
hidden and no glyph is painted.

**Themeable custom properties:** `--lr-radio-group-row-gap` (default
`calc(var(--lr-form-control-height) * 0.2)`) — the vertical gap between the group's label, its
options and its messages, scaled by `size` through the shared control ladder.

**Methods:** `setCustomValidity(message = '')` sets or clears a group-level consumer error. A
non-empty message raises `customError` and blocks submission; `setCustomValidity('')` and
`resetValidity()` restore the group's computed validity, including `valueMissing` when a required
group has no selected radio. `focus()` moves focus to the selected (or first enabled) radio;
`blur()` releases whichever owned radio currently contains deep focus, and `click()` mirrors
`focus()` by activating the selected/first enabled radio. All three are inert under direct or
fieldset disablement, so the group behaves like one native control.
