Skip to content

Radio group

Choose one answer from a short list, cards or a segmented bar; the whole row or card is the click target.

<script setup lang="ts">import { ref } from 'vue'import { UiRadioGroup, UiRadio } from 'grani' const delivery = ref('door')</script> <template>  <UiRadioGroup v-model="delivery" aria-label="Delivery" class="w-80">    <UiRadio value="door">      Leave the parcel at the door if nobody answers, and send a photo of where it was left    </UiRadio>    <UiRadio value="neighbor" description="The courier rings the flat next door">      Hand it to a neighbor    </UiRadio>    <UiRadio value="point" description="Not in your area yet" disabled>      Take it to a pickup point    </UiRadio>  </UiRadioGroup></template>

Also called radio buttons, segmented control, option cards.

Usage

<UiRadioGroup v-model="value">…</UiRadioGroup>

With GraniResolver in the Vite config, a template needs no import: set it up once.

API

Name · typeDefaultDescription
Value
modelValue*SelectValue | nullThe selected value (v-model). null when nothing is selected.
Look
variantplain | card | card-check | segmented= "plain""plain"plain rows with the mark first; card a card per radio with the mark at the end; card-check cards that show a check and a tint on the selected one only; segmented a bar with one segment pressed.
sizexs | sm | mdStep of the control ladder. A segmented bar is 36 or 44 px (xs is read as sm: a 24px segment is too small to hit); a plain mark is 16, 18 or 20 px. Unset, the app's size (createGrani({ size })).
blockboolean= falsefalseA segmented bar as wide as its row, segments sharing the width.
Form and access
namestringNative name shared by every radio, for forms. Generated when omitted, stable across server and client; two apps on one page need their own app.config.idPrefix.
disabledboolean= falsefalsePrevents selecting in every radio.
invalidboolean= falsefalseMarks the group as invalid: red marks. Inside UiField, the error state sets this automatically.
idstringOwn id of the group, for a reference from elsewhere (aria-controls, a link); a field names it by its legend.
ariaLabelstringAccessible name of the group when there is no visible legend. Inside a UiField group the legend names it.
requiredboolean= falsefalseOne answer is needed: said to a reader on the group, and required on the radios for a form. Inside UiField group the legend says it instead.

Attributes: class and style stay on the outer element; the rest (native attributes, aria-*, data-testid) reach the control inside it.

Radio

Name · typeDefaultDescription
value*SelectValueThe value this radio stands for; the group's model takes it when selected.
descriptionstringA second line under the label. Read with the radio as its description. Not drawn in a segment.
disabledboolean= falsefalsePrevents selecting this radio; the group's disabled covers all of them.
idstringOwn id, for a label elsewhere.
ariaLabelstringAccessible name when the slot has no text: a glyph segment, a label outside the row.

Attributes: class and style stay on the outer element; the rest (native attributes, aria-*, data-testid) reach the control inside it.

When to use another component

When you needTake
Several answersCheckbox in a Field group
A mark from 1 to NScale input
A pick from a long listSelect
On or offSwitch
Sections of a page, each with its own contentTabs
Actions side by sideButton group