Lynx/Modules/Zero/RadioGroup
@sigx/lynx-zero · Beta · Component library

RadioGroup#

One choice from a set, under a string model, on zero's radio-group anatomy. Each item row is its own tap target and accessibility element. Lynx has no native radios, so there is no shared name, no hidden input and no arrow-key roving.

The parts and states are the same as the web component's. See Radio Group in @sigx/zero for the shared contract. This page covers what is different on Lynx.

Import#

TSX
import { RadioGroup } from '@sigx/lynx-zero';

RadioGroup is a compound with Root, Item and Label. <RadioGroup> is the same component as <RadioGroup.Root>.

Usage#

TSX
import { component, signal } from '@sigx/lynx';
import { RadioGroup } from '@sigx/lynx-zero';

export const Plan = component(() => {
    const state = signal({ plan: 'free' });
    return () => (
        <RadioGroup.Root model={() => state.plan} color="primary">
            <RadioGroup.Label>Plan</RadioGroup.Label>
            <RadioGroup.Item value="free">Free</RadioGroup.Item>
            <RadioGroup.Item value="pro">Pro</RadioGroup.Item>
            <RadioGroup.Item value="team" disabled>Team</RadioGroup.Item>
        </RadioGroup.Root>
    );
});

The model is the chosen item's value. '' means nothing is chosen, which is the default. Tapping the checked item does nothing, because a radio never unchecks. An item's default slot is its label text and renders inside a <text>, so pass a string.

Data mode#

Pass items instead of children and the group renders one item per entry. The accessors are the same ones Select takes:

TSX
const plans = [
    { id: 'free', name: 'Free' },
    { id: 'pro', name: 'Pro' },
    { id: 'team', name: 'Team', disabled: true },
];

<RadioGroup.Root
    items={plans}
    itemKey={(p) => p.id}
    itemLabel={(p) => p.name}
    model={() => state.plan}
/>
  • itemKey gives the model string for an item. By default it reads value or id, or uses the item itself when it is a primitive.
  • itemLabel gives the label text. By default it reads label, or falls back to the key.
  • itemDisabled defaults to item.disabled === true.
  • The item slot renders a custom label for a generated item. It receives { item }. The label text still names the item for a screen reader.

Explicit children win entirely: when the group has children, items is ignored. An item keyed '' throws, because it could never be told apart from "nothing chosen".

Flags#

disabled, invalid, required and readonly on the root are each the prop OR an enclosing Field.Root's. invalid and readonly are restated on every item and its control, the surfaces a skin paints. A read-only group keeps every item announced but refuses every tap and shows no press. disabled on one item disables only that item. The group also takes the Field's size when it sets none.

Props#

RadioGroup.Root#

PropTypeDefaultDescription
modelstring—Two-way binding of the chosen value. '' is nothing chosen.
defaultValuestring''Initial value when uncontrolled.
itemsReadonlyArray<T>—Data mode: one item per entry. Ignored when the group has children.
itemKey(item: T) => stringvalue / id, or the primitiveThe model string for an item.
itemLabel(item: T) => stringlabel, or the keyThe label text for an item.
itemDisabled(item: T) => booleanitem.disabled === trueWhether an item is disabled.
orientation'horizontal' | 'vertical''vertical'The axis the items are laid out along. Stamped on the root.
disabledbooleanfalseDisables every item. ORed with the Field's.
invalidbooleanfalseRestated on every item and item control. ORed with the Field's.
requiredbooleanfalseA flag the skin and the reader see. ORed with the Field's.
readonlybooleanfalseEvery item announced, none changes the value. ORed with the Field's.
color / sizestringskin defaultThe design system's axes, stamped on every part. size falls back to the Field's.
classstring—Extra classes, appended after the computed ones.

RadioGroup.Item#

PropTypeDefaultDescription
valuestring—Required. The model value this item selects.
disabledbooleanfalseDisables this item. ORed with the group's.
labelstring—Accessible name. The visible label is the default slot.
classstring—Extra classes.

RadioGroup.Label#

The group's visible name, a <text> part. Takes class and a default slot.

Events#

EventPayloadDescription
valueChange (onValueChange)stringThe chosen value changed.

Slots#

SlotPartDescription
defaultRootExplicit RadioGroup.Label and RadioGroup.Item children.
itemRootA custom label for a generated item, given { item }.
defaultItemThe item's label text.

Anatomy on Lynx#

PartElementStatesFlags
rootview— (orientation horizontal | vertical)disabled, invalid, required, readonly
labeltext—disabled, invalid, required
itemview (button trait, the tap target)checked | uncheckeddisabled, invalid, readonly
item-controlviewsamedisabled, invalid, readonly, pressed
item-indicatorviewsame—
item-labeltextsamedisabled

The group root is not an accessibility element, so each item announces itself: checked or unchecked, then disabled or read only. The pressed flag rides the item-control while a touch is held.

Not taken on Lynx: the hidden-input part, the generated name, form, arrow-key roving and native validity. focus-visible can only be forced for display, through ForceStates from @sigx/lynx-zero/testing.

See also#