GrRadio
A single choice within a group of mutually exclusive options.
Overview
When to take it
- the switch stands on its own — an option in a table row, in a card, in a list cell: there is no group around it;
- the layout is set by the consumer — the options are laid out on a grid of their own rather than in a row or a column;
- the look of a button —
variant="button"gives the appearance ofGrButtonwhile keeping theradiorole; - the label is complex — the slot accepts markup: a price, a badge, an icon.
When to take something else
| Need | Take |
|---|---|
| There are several options and they stand side by side | GrRadioGroup |
| Several can be selected | GrCheckbox |
| There are 2–5 options and they switch a view | GrSegmented |
| There are more than seven options | GrSelect |
Outside GrRadioGroup the keyboard contract of the radiogroup pattern does not work: the
arrows between options are walked by the container. A single GrRadio is a deliberate refusal of
it for the sake of a layout of your own rather than a simplification.
Variants every tone and view, rendered by the real component
variant
radioboxbutton
Sizes
xssmmdlg
States
normaldisabledinvalid
The grid is live: hover and press it. Hover, focus and active states are not drawn here — they belong to the browser, not to a prop.
Playground controls come from the API, not from hand
Loading…
0 changed· state is in the URL
<GrRadio>Label</GrRadio>Examples 3 each with a live demo and its code
Plans as cards
Separate radios with one
namemake a group of cards: a click anywhere on a card chooses its plan, the radio inside keeps the keyboard, and thedescriptionslot puts the note inside the radio’s accessible name — the difference between plans is what the choice is made on.A delivery option with its own field
Separate radios let content live between the options: the parcel point is chosen right under its option, which an
optionslist cannot do. The select stays in place and is enabled only with its option, so the form does not jump; adisabledoption keeps saying why.A period in a card header
variant="button"changes the drawing, not the semantics: one name, arrow keys between the options. Quiet buttons fit a card header —button-variant="ghost"at rest, a filled neutral one when chosen throughselected-button-variantandselected-button-tone.Revenue€76,900 +6.1%
API generated from the package · cannot drift
Props
| Prop | Type | default | Description |
|---|---|---|---|
disabled | boolean | undefined | undefined | The radio is unavailable. Unset — taken from the group. |
variant | GrRadioVariant | undefined | "radiobox" | The look: `radiobox` — a circle with a dot and a label, `button` — a button in the style of `GrButton`. `radiobox` by default. |
modelValuev-model | GrRadioValue | undefined | undefined | The selected value (`v-model`) of a standalone radio. In a group the group holds the value. |
invalid | boolean | undefined | false | The visual and ARIA state of an error. It adds up with the `invalid` of the group. |
required | boolean | undefined | false | A choice is required: `aria-required` on the radio. |
size | "xs" | "sm" | "md" | "lg" | undefined | undefined | The size on the button scale. Unset — from the group, then `GrConfigProvider`, otherwise `md`. |
ariaLabel | string | undefined | undefined | The accessible name when there is no label in the slot — for example, for an icon-only button. |
name | string | undefined | undefined | The name for a native form: the selected radio submits its value in a hidden field. Unset — from the group. |
id | string | undefined | undefined | The `id` of the element with the `radio` role — for references to it from outside. |
form | string | undefined | undefined | The `form` of the hidden field — when the form the value goes to is not around the radio. |
buttonVariant | GrButtonVariant | undefined | "outline" | The weight of an unselected button in `variant="button"`. `outline` by default. |
buttonTone |
| "neutral" | The tone of an unselected button in `variant="button"`. `neutral` by default. |
selectedButtonVariant | GrButtonVariant | undefined | "primary" | The weight of the selected button in `variant="button"`. `primary` by default. |
selectedButtonTone |
| "primary" | The tone of the selected button in `variant="button"`. `primary` by default. |
valuerequired | GrRadioValue | — | The value of the radio: it is selected when the value matches `modelValue` or the value of the group. |
Slots
| Slot | Type | Description |
|---|---|---|
default | any | The label of the radio instead of the `label` prop. |
description | any | An explanation under the label. |
Events
| Event | Signature | Description |
|---|---|---|
update:modelValue | (event: "update:modelValue", value: GrRadioValue): void | — |
Types
Every exported type of the subpath, grouped by the file it lives in. Names, generics and bodies come from the package’s declaration files and cannot drift.
import type { GrRadioProps, GrRadioEmits, GrRadioConfigurableProps } from '@feugene/granularity/components/GrRadio'Filedist/types/components/GrRadio/GrRadio.vue.d.ts
interface GrRadioProps {
value: GrRadioValue;
modelValue?: GrRadioValue;
disabled?: boolean;
invalid?: boolean;
name?: string;
required?: boolean;
form?: string;
id?: string;
size?: GrButtonSize;
variant?: GrRadioVariant;
buttonVariant?: GrButtonVariant;
buttonTone?: GrButtonTone;
selectedButtonVariant?: GrButtonVariant;
selectedButtonTone?: GrButtonTone;
ariaLabel?: string;
}interface GrRadioEmits {
(e: 'update:modelValue', value: GrRadioValue): void;
}Filedist/types/components/GrRadio/config.d.ts
const grRadioConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrRadio">;Filedist/types/components/GrRadio/defaults.d.ts
interface GrRadioConfigurableProps {
size: GrButtonSize;
}Filedist/types/components/GrRadio/grRadioStyles.d.ts
type GrRadioVariant = 'radiobox' | 'button';Filedist/types/components/GrRadio/grRadioGroupContext.d.ts
type GrRadioGroupContext = {
modelValue: ComputedRef<GrRadioValue>;
name: ComputedRef<string | undefined>;
disabled: ComputedRef<boolean>;
readonly: ComputedRef<boolean>;
invalid: ComputedRef<boolean>;
size: ComputedRef<GrButtonSize>;
setValue: (value: GrRadioValue) => void;Filedist/types/components/GrRadio/safelist.d.ts
const grRadioSafelist: string[];Accessibility
APG pattern
radio
Keys
Enter↑ / ←
Full contract of the package: docs/keyboard.md ↗
Usage from the library prose
The keyboard: the group is one Tab stop
| Key | What it does |
|---|---|
Tab | enters the group and leaves it; inside the group there is exactly one stop (a roving tabindex) |
↓ / → | the next option, in a ring |
↑ / ← | the previous option, in a ring |
Home / End | the first / the last available option |
Space, Enter | select the current one (for a standalone switch) |
The selection travels with the focus — that is what the radiogroup pattern requires. Disabled
options are skipped: they take part neither in the roving tabindex nor in the walk with the
arrows.
The state lives in GrRadioGroup (register / rovingValue / moveSelection / selectEdge in
the context), and GrRadio asks the group whether it is the focusable one right now. A standalone
switch outside a group remains an ordinary Tab stop.
The label and the description
<GrRadio value="pro">
Pro
<template #description>
Charged monthly, can be cancelled at any moment
</template>
</GrRadio>The label of a selected option is --gr-fg, of an unselected one --gr-muted-fg: before that any
of them was dimmed, and the selected option was not distinguished by text at all.
The #description slot is linked to the switch through aria-describedby — otherwise the
description does not exist for a screen reader.
The values
value and modelValue are string | number | boolean (GrRadioValue). Enumerations in real
forms are usually an id as a number or a flag. Objects are deliberately not included: the value
travels into data-value and into the hidden input of a native form, which means it has to have
an unambiguous string representation.
The error and the disabled state
invalid can be set on the switch itself or on the whole group — the states add by “or”. The
border of the control is coloured --gr-danger, and aria-invalid goes onto the element.
A disabled switch is dimmed with tokens (--gr-muted / --gr-muted-fg) rather than with
transparency: opacity dilutes colours tuned to AA. The button variant takes its disabled look
from GrButton itself — there it depends on the variant.
The native form
An input[type="hidden"] is rendered beside the switch — only for the selected and non-disabled
element and only when name is set, as a native radio would do. Nothing interactive is nested
inside an element with role="radio": the role declares its descendants presentational, and a
hidden <input type="radio"> would break the widget for a screen reader (axe:
nested-interactive).
Props in this example