GrRadio
Берут, когда переключатель стоит отдельно.
Обзор
Когда брать
- переключатель стоит отдельно — вариант в строке таблицы, в карточке, в ячейке списка: группы вокруг него нет;
- раскладку задаёт потребитель — варианты разложены по своей сетке, а не в ряд или столбец;
- вид кнопки —
variant="button"даёт внешностьGrButton, оставляя рольradio; - подпись сложная — слот принимает разметку: цену, бейдж, иконку.
Когда взять другое
| Нужно | Берите |
|---|---|
| Вариантов несколько и они рядом | GrRadioGroup |
| Можно выбрать несколько | GrCheckbox |
| Вариантов 2–5 и они переключают вид | GrSegmented |
| Вариантов больше семи | GrSelect |
Вне GrRadioGroup клавиатурный контракт паттерна radiogroup не работает:
стрелки между вариантами водит контейнер. Одиночный GrRadio — это осознанный
отказ от него ради своей раскладки, а не упрощение.
Варианты все тона и виды — настоящим компонентом
variant
radioboxbutton
Размеры
xssmmdlg
Состояния
обычнаяdisabledinvalid
Матрица живая: наводите и нажимайте. Состояний наведения, фокуса и нажатия здесь нет — они за браузером, а не за пропом.
Playground контролы выводятся из API, а не пишутся руками
Загружается…
0 изменено· состояние — в адресе
<GrRadio>Текст</GrRadio>Примеры 3 у каждого — живое демо и его код
Тарифы карточками
Отдельные переключатели с одним
nameсобирают группу карточек: клик в любом месте карточки выбирает тариф, переключатель внутри держит клавиатуру, а слотdescriptionкладёт пояснение в доступное имя — по нему и выбирают.Вариант доставки со своим полем
Отдельные переключатели позволяют поместить содержимое между вариантами: пункт выдачи выбирается прямо под своим вариантом, чего список
optionsне умеет. Выпадающий список стоит на месте и включается только со своим вариантом, поэтому форма не прыгает;disabled-вариант продолжает объяснять почему.Период в шапке карточки
variant="button"меняет рисунок, а не смысл: одно имя, стрелки между вариантами. В шапку карточки подходят тихие кнопки —button-variant="ghost"в покое и заполненная нейтральная при выборе черезselected-button-variantиselected-button-tone.Revenue€76,900 +6.1%
API порождается из пакета · разойтись не может
Props
| Prop | Type | по умолчанию | Описание |
|---|---|---|---|
disabled | boolean | undefined | undefined | Переключатель недоступен. Не задан — берётся из группы. |
variant | GrRadioVariant | undefined | "radiobox" | Вид: `radiobox` — круг с точкой и подписью, `button` — кнопка в стиле `GrButton`. По умолчанию `radiobox`. |
modelValuev-model | GrRadioValue | undefined | undefined | Выбранное значение (`v-model`) у одиночного переключателя. В группе значение ведёт она. |
invalid | boolean | undefined | false | Визуальное и ARIA-состояние ошибки. Складывается с `invalid` группы. |
required | boolean | undefined | false | Выбор обязателен: `aria-required` на переключателе. |
size | "xs" | "sm" | "md" | "lg" | undefined | undefined | Размер по шкале кнопок. Не задан — из группы, затем `GrConfigProvider`, иначе `md`. |
ariaLabel | string | undefined | undefined | Доступное имя, когда подписи в слоте нет — например, у кнопки из одной иконки. |
name | string | undefined | undefined | Имя для нативной формы: выбранный отдаёт значение скрытым полем. Не задано — из группы. |
id | string | undefined | undefined | `id` элемента с ролью `radio` — для ссылок на него извне. |
form | string | undefined | undefined | `form` скрытого поля — когда форма, куда уходит значение, стоит не вокруг переключателя. |
buttonVariant | GrButtonVariant | undefined | "outline" | Вес невыбранной кнопки в `variant="button"`. По умолчанию `outline`. |
buttonTone |
| "neutral" | Тон невыбранной кнопки в `variant="button"`. По умолчанию `neutral`. |
selectedButtonVariant | GrButtonVariant | undefined | "primary" | Вес выбранной кнопки в `variant="button"`. По умолчанию `primary`. |
selectedButtonTone |
| "primary" | Тон выбранной кнопки в `variant="button"`. По умолчанию `primary`. |
valueобязательный | GrRadioValue | — | Значение переключателя: он выбран, когда оно совпадает с `modelValue` или значением группы. |
Слоты
| Slot | Type | Описание |
|---|---|---|
default | any | Подпись переключателя вместо пропа `label`. |
description | any | Пояснение под подписью. |
События
| Event | Сигнатура | Описание |
|---|---|---|
update:modelValue | (event: "update:modelValue", value: GrRadioValue): void | — |
Типы
Все экспортируемые типы подпути, по файлам, где они объявлены. Имена, дженерики и тела читаются из файлов деклараций пакета и разойтись не могут.
import type { GrRadioProps, GrRadioEmits, GrRadioConfigurableProps } from '@feugene/granularity/components/GrRadio'Файлdist/types/components/GrRadio/GrRadio.vue.d.ts
GrRadio — одиночный элемент группы выбора.
Может работать автономно (через v-model) либо внутри GrRadioGroup
(тогда modelValue/disabled/size/name/invalid приходят через inject).
Доступным контролом является сам элемент с role="radio": он держит фокус,
aria-checked и клавиатуру. Внутрь него ничего интерактивного не вкладывается —
role="radio" объявляет потомков презентационными, и вложенный native <input>
(даже скрытый и с tabindex="-1") ломает виджет для скринридеров и падает
в axe на nested-interactive. Для отправки нативной формой рядом рендерится
input[type="hidden"] — он не фокусируется и не является интерактивным.
interface GrRadioProps {
/** Значение переключателя: он выбран, когда оно совпадает с `modelValue` или значением группы. */
value: GrRadioValue;
/** Выбранное значение (`v-model`) у одиночного переключателя. В группе значение ведёт она. */
modelValue?: GrRadioValue;
/** Переключатель недоступен. Не задан — берётся из группы. */
disabled?: boolean;
/** Визуальное и ARIA-состояние ошибки. Складывается с `invalid` группы. */
invalid?: boolean;
/** Имя для нативной формы: выбранный отдаёт значение скрытым полем. Не задано — из группы. */
name?: string;
/** Выбор обязателен: `aria-required` на переключателе. */
required?: boolean;
/** `form` скрытого поля — когда форма, куда уходит значение, стоит не вокруг переключателя. */
form?: string;
/** `id` элемента с ролью `radio` — для ссылок на него извне. */
id?: string;
/** Размер по шкале кнопок. Не задан — из группы, затем `GrConfigProvider`, иначе `md`. */
size?: GrButtonSize;
/**
* Вид: `radiobox` — круг с точкой и подписью, `button` — кнопка в стиле `GrButton`.
* По умолчанию `radiobox`.
*/
variant?: GrRadioVariant;
/** Вес невыбранной кнопки в `variant="button"`. По умолчанию `outline`. */
buttonVariant?: GrButtonVariant;
/** Тон невыбранной кнопки в `variant="button"`. По умолчанию `neutral`. */
buttonTone?: GrButtonTone;
/** Вес выбранной кнопки в `variant="button"`. По умолчанию `primary`. */
selectedButtonVariant?: GrButtonVariant;
/** Тон выбранной кнопки в `variant="button"`. По умолчанию `primary`. */
selectedButtonTone?: GrButtonTone;
/** Доступное имя, когда подписи в слоте нет — например, у кнопки из одной иконки. */
ariaLabel?: string;
}interface GrRadioEmits {
/** Выбран этот переключатель (`v-model`). Только при заданном `modelValue`, иначе выбор у группы. */
(e: 'update:modelValue', value: GrRadioValue): void;
}Файлdist/types/components/GrRadio/config.d.ts
const grRadioConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrRadio">;Файлdist/types/components/GrRadio/defaults.d.ts
Пропы GrRadio, настраиваемые глобально через
<GrConfigProvider :component-defaults="{ GrRadio: { … } }">.
Только оформление — см. GrButton/defaults.ts.
interface GrRadioConfigurableProps {
size: GrButtonSize;
}Файлdist/types/components/GrRadio/grRadioStyles.d.ts
type GrRadioVariant = 'radiobox' | 'button';Файлdist/types/components/GrRadio/grRadioGroupContext.d.ts
type GrRadioGroupContext = {
modelValue: ComputedRef<GrRadioValue>;
name: ComputedRef<string | undefined>;
disabled: ComputedRef<boolean>;
/**
* Только для чтения: выбор видно, но он не меняется. У роли `radio` нет
* `aria-readonly` — состояние объявляет сама группа, переключателю остаётся
* не прикидываться кликабельным.
*/
readonly: ComputedRef<boolean>;
/** Ошибка группы: до вида переключателя она доходит только через контекст. */
invalid: ComputedRef<boolean>;
size: ComputedRef<GrButtonSize>;
setValue: (value: GrRadioValue) => void;Файлdist/types/components/GrRadio/safelist.d.ts
Пуст: собственных составных классов у переключателя нет. radiobox и
отключённая кнопка-радио выбирают классы целыми литералами из
grRadioStyles.ts и шаблона — granum извлекает их из чанков компонента сам,
включая общие.
Вид button строит grRadioStyles.ts: grRadioButtonClass через
grButtonClass из GrButton/grButtonStyles.ts: матрицу тон × вариант там
клеит variantClass, база и размеры лежат литералами. Модуль живёт в чанке
GrButton, обход от входа GrRadio на нём останавливается как на ребре, и
все эти классы приезжают зависимостью GrButton: литералы её чанка извлекаются
у неё, матрицу объявляет grButtonSafelist. Повторять их здесь незачем.
const grRadioSafelist: string[];Доступность
Паттерн APG
radio
Клавиши
Enter↑ / ←
| Клавиша | Действие |
|---|---|
| — | Space |
| Enter | выбрать; ↓/→ — следующий |
| ↑ / ← | предыдущий (выбор едет вместе с фокусом, по кругу); Home/End — первый/последний доступный. Группа — одна остановка Tab, отключённые варианты пропускаются |
Полный контракт пакета: docs/keyboard.md ↗
Использование из прозы библиотеки
Клавиатура: группа — одна остановка Tab
| Клавиша | Что делает |
|---|---|
Tab | входит в группу и выходит из неё; внутри группы остановка ровно одна (roving tabindex) |
↓ / → | следующий вариант, по кругу |
↑ / ← | предыдущий вариант, по кругу |
Home / End | первый / последний доступный вариант |
Space, Enter | выбрать текущий (для автономного переключателя) |
Выбор едет вместе с фокусом — так требует паттерн radiogroup. Отключённые
варианты пропускаются: они не участвуют ни в roving tabindex, ни в обходе
стрелками.
Состояние живёт в GrRadioGroup (register / rovingValue / moveSelection /
selectEdge в контексте), а GrRadio спрашивает у группы, он ли сейчас
фокусируемый. Автономный переключатель вне группы остаётся обычной остановкой
Tab.
Подпись и описание
<GrRadio value="pro">
Pro
<template #description>
Списывается ежемесячно, можно отменить в любой момент
</template>
</GrRadio>Подпись выбранного варианта — --gr-fg, невыбранного — --gr-muted-fg: до
этого приглушённой была любая, и выбранный вариант не выделялся текстом вовсе.
Слот #description связывается с переключателем через aria-describedby —
иначе для скринридера описания не существует.
Значения
value и modelValue — string | number | boolean (GrRadioValue).
Перечисления в реальных формах это обычно id числом или флаг. Объекты сюда не
входят намеренно: значение уходит в data-value и в скрытый input нативной
формы, а значит должно иметь однозначное строковое представление.
Ошибка и отключённое состояние
invalid можно поставить самому переключателю или всей группе — состояния
складываются по «или». Рамка контрола красится --gr-danger, на элемент идёт
aria-invalid.
Отключённый переключатель гасится токенами (--gr-muted / --gr-muted-fg), а
не прозрачностью: opacity разбавляет выверенные на AA цвета. Кнопочный вариант
берёт отключённый вид у самого GrButton — там он вариант-зависимый.
Нативная форма
Рядом с переключателем рендерится input[type="hidden"] — только у выбранного
и не-disabled элемента и только при заданном name, как поступил бы нативный
radio. Внутрь элемента с role="radio" ничего интерактивного не вкладывается:
роль объявляет потомков презентационными, и скрытый <input type="radio">
сломал бы виджет для скринридера (axe: nested-interactive).
Пропы этого примера