v1.0.0

<bmx-radio-group>

One answer from several. The group holds the value, the keyboard, the tab order, the form participation and the validity; bmx-radio renders an option and nothing more. That division is what makes two options selected at once impossible rather than merely unlikely.

15 properties · 2 events · 4 methods · 4 parts

Example

Show markup
<div class="row">
  <bmx-radio-group label="Contact me by" value="email" description="Arrow keys move and choose in one keystroke, as they do in a native radio group.">
    <bmx-radio value="email" label="Email"></bmx-radio>
    <bmx-radio value="post" label="Post"></bmx-radio>
    <bmx-radio value="phone" label="Telephone"></bmx-radio>
  </bmx-radio-group>
</div>
<div class="row">
  <bmx-radio-group label="Delivery" orientation="horizontal" required="true">
    <bmx-radio value="standard" label="Standard"></bmx-radio>
    <bmx-radio value="express" label="Express"></bmx-radio>
    <bmx-radio value="collect" label="Click and collect" disabled="true"></bmx-radio>
  </bmx-radio-group>
</div>

THE KEYBOARD IS NOT A TOOLBAR'S

A radio group and a button group both take one Tab stop and move on the arrows, and there the resemblance ends:

  • Arrow keys select. Moving to an option chooses it, in one keystroke. There is no way to look at an option without selecting it, which is how every native radio group on every platform behaves and what a user who presses Down expects.
  • Both axes always work. Up and Left move back, Down and Right move forward, whether the group is a column or a row. A radio group is a list of answers rather than a strip of controls.
  • Tabbing in lands on the answer, not on wherever focus happened to be left. Landing anywhere else invites the user to press an arrow key and change a value they only meant to look at.

The arithmetic for all three is in src/core/choice.ts, unit tested. The component's job is to read the options, hand them their tabindex, and move focus - which is the part that needs a browser.

WHY THE ROLE IS ON A DIV INSIDE THE SHADOW ROOT

role="radiogroup" needs an accessible name, and the group's caption lives in this component's shadow root. An aria-labelledby on the host could not see it: IDREF attributes do not cross a shadow boundary, so the reference would silently resolve to nothing and the group would be announced as an unnamed group - which is the failure mode that looks completely fine.

Putting the role on a <div> beside the caption puts both in the same root, so the reference resolves. The slotted options are still inside it where the accessibility tree is concerned, because that tree is built from the flattened tree and the <slot> is in the div.

Properties

PropertyAttributeTypeDefaultDescription
description description string Help text below the options.
disabled disabled boolean false Disable every option in the group. Options may still be disabled individually.
errorText error-text string An error supplied by the consumer - a server response, typically.
fullWidth full-width boolean false Stretch to the width of the container.
hideLabel hide-label boolean false Hide the caption visually while keeping it as the accessible name.
label label string The group's caption - the question the options answer. Not optional in practice: a radiogroup announced with no name tells a screen reader user only that some options have been grouped, and the options themselves rarely make sense without the question.
messages property only BmxFieldMessages Replacements for the default wording, by reason. Accepts the JSON spelling of the object as well, for templates that can only write attributes. See src/core/markup.ts.
name name string The field's name in the form it belongs to.
orientation orientation BmxOrientation 'vertical' Layout direction. Both axes move the selection either way; this is visual.
required required boolean false Require an answer before the form will submit.
size size BmxSize 'md' Applied to every option that has not set its own.
tone tone BmxTone 'primary' Applied to every option that has not set its own.
validateOn validate-on BmxValidateOn 'blur' When the group is willing to reveal a problem.
value value string | null null The chosen option's value. Two-way: the group writes back to it.
wrapFocus wrap-focus boolean true Whether arrowing past the last option returns to the first.

Events

EventDetailDescription
bmxChange BmxRadioGroupChangeDetail Fired when the chosen option changes.
bmxValidityChange BmxRadioGroupValidityDetail Fired whenever the resolved validity changes.

Methods

MethodSignatureDescription
checkValidity checkValidity() => Promise<boolean> Validate now and return whether the group passed, without revealing anything.
refresh refresh() => Promise<void> Re-read the options. Call after adding or removing them imperatively.
reportValidity reportValidity() => Promise<boolean> Validate, reveal any problem, and focus the group if it has one.
setFocus setFocus() => Promise<void> Move focus to the group - onto the chosen option, or the first available one.

Slots

SlotDescription
(default) bmx-radio elements.
description Rich help text, in place of the description property.
label Rich caption content, in place of the label property.

CSS shadow parts

PartDescription
base The element carrying role="radiogroup".
description The help text.
error The error message.
label The group's caption.

CSS custom properties

PropertyDescription
--bmx-radio-group-gap Space between the options.
--bmx-radio-group-label-font-size The question's font size.
--bmx-radio-group-stack-gap Space between the question, the options and the supporting text.
--bmx-radio-group-support-font-size Font size of the description and error message.