CSC Design System next
VueFlavour Vue React Angular TypeScript PrimaryCSC UI ColorsPrimarySecondaryAccentCustom ColorsRedOrangeGreenBluePurplePink
Guides Getting started Customization Data visualization Migration guide Componentsc-accordionc-alertc-autocompletec-badgec-buttonc-button-groupc-cardc-checkboxc-csc-logoc-data-tablec-dividerc-iconc-icon-buttonc-inputc-linkc-listc-loaderc-login-buttonsc-login-cardc-mainc-menuc-messagec-modalc-navigation-buttonc-otp-inputc-pagec-paginationc-popoverc-progress-barc-progress-circlec-radio-groupc-selectc-side-navigationc-sliderc-spinnerc-statusc-stepsc-switchc-tablec-tabsc-tagsc-text-fieldc-toastsc-toolbarc-tooltip

<c-radio-group>

A radio group is a set of mutually exclusive choices where exactly one can be selected, authored as slotted `c-radio` children. Give the group a `label` so the choice it represents is named for every user, and a `hint` describing how to answer.

Usage

Authoring the options

Each option is a <c-radio value="..."> whose default slot is its label — keep the label text (or richer markup) inside the radio so it stays clickable and is announced with the control:

<c-radio-group label="Subscription plan" value="free">
  <c-radio value="free">Free</c-radio>
  <c-radio value="paid">Paid</c-radio>
</c-radio-group>

The radios may sit at any depth inside the default slot, so custom layouts are plain markup — wrap each radio in whatever layout element the design needs:

<c-radio-group label="Subscription plan" value="free">
  <div class="card"><c-radio value="free">Free</c-radio></div>
  <div class="card"><c-radio value="paid">Paid</c-radio></div>
</c-radio-group>

Text placed next to a radio instead of inside it renders, but is not click-associated or announced — put the label content in the radio's slot.

Value

The group's value is the selected radio's value, matched by strict string equality; the group holds string values only. Selection is expressed solely through the group — radios carry no checked state of their own. Giving two radios the same value is a consumer error: every matching radio will show as checked.

In Vue, bind with a plain v-model. The group also emits its radios' bubbling change events onward, with the selected c-radio as the event target.

Label

The label prop names the group; when richer label content is needed, use the label slot instead (the prop wins when both are set). The default slot is exclusively the radios' home — loose text there is not treated as a label.

Validation

Validation is your job: set valid to false and supply an error-message explaining why. While invalid without an error-message, the hint keeps rendering as a hint. The message area reserves its height (unless hide-details), so an error appearing at runtime doesn't shift the layout.

Accessibility

The group is announced as a radiogroup named by its label. Keyboard behavior follows the native pattern: Tab moves into the group (onto the checked radio, or the first enabled one) and out of it in one stop; the arrow keys move between radios, selecting as they go, wrapping at the ends and skipping disabled radios; Space selects the focused radio. Enter is left to the surrounding form.

Examples

Basic
Vue React Angular TypeScript
<template>
  <div>
    <c-radio-group
      v-model="plan"
      hint="You can change the plan later"
      label="Subscription plan"
    >
      <c-radio value="free">Free</c-radio>

      <c-radio value="pro">Pro</c-radio>

      <c-radio value="enterprise">Enterprise</c-radio>
    </c-radio-group>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const plan = ref('free');
</script>
Custom layout
Vue React Angular TypeScript
<template>
  <div>
    <c-radio-group
      v-model="plan"
      hint="You can change the plan later"
      label="Subscription plan"
    >
      <div class="plan-option">
        <c-radio value="free">Free</c-radio>
      </div>

      <div class="plan-option">
        <c-radio value="pro">Pro</c-radio>
      </div>

      <div class="plan-option">
        <c-radio value="enterprise">Enterprise</c-radio>
      </div>
    </c-radio-group>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const plan = ref('free');
</script>

<style>
/* The radios are ordinary light DOM: wrap them in your own layout markup and
   style it with your own CSS. Keep the label text inside the <c-radio> so the
   whole row stays click-associated. */
.plan-option {
  border: 1px solid var(--c-border);
  border-radius: 0.5rem;
  padding: 0 0.75rem;
}
</style>
Inline
Vue React Angular TypeScript
<template>
  <div>
    <c-radio-group
      v-model="frequency"
      hide-details
      inline
      label="Email frequency"
    >
      <c-radio value="daily">Daily</c-radio>

      <c-radio value="weekly">Weekly</c-radio>

      <c-radio value="never">Never</c-radio>
    </c-radio-group>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const frequency = ref('weekly');
</script>
Basic · c-radio
Vue React Angular TypeScript
<template>
  <div>
    <c-radio-group
      v-model="plan"
      hint="You can change the plan later"
      label="Subscription plan"
    >
      <c-radio value="free">Free</c-radio>

      <c-radio value="pro">Pro</c-radio>

      <c-radio value="enterprise" disabled>Enterprise</c-radio>
    </c-radio-group>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const plan = ref('free');
</script>

API reference

<c-radio-group>

A radio group is a set of mutually exclusive choices where exactly one can be selected, authored as slotted `c-radio` children. Give the group a `label` so the choice it represents is named for every user, and a `hint` describing how to answer.

Properties

PropertyAttributeTypeDefaultDescription
disableddisabledbooleanfalseDisable the radio group
errorMessageerror-messagestring''Error message shown in place of the hint while the group is invalid
hideDetailshide-detailsbooleanfalseHide the hint and error messages
hinthintstring''Hint text for the input
inlineinlinebooleanfalseDisplay radio buttons inline
labellabelstring''Label of the radio group
requiredrequiredbooleanfalseSet as required
validvalidbooleantrueSet the validity of the input
valuevaluenull | stringnullValue of the radio group; matched against each radio's `value` by strict string equality

Events

EventDetailDescription
changeValuestringFired when a radio is selected, carrying the selected radio's value. Also dispatched as `change-value` — bind that name in Vue templates.
inputvoidNative bubbling input event fired on selection so a plain Vue `v-model` works without the `v-control` directive. No detail.
update:valuestringv-model contract event fired on selection, carrying the selected radio's value.

Slots

SlotDescription
defaultThe radios' home: `<c-radio>` children, wrappable in arbitrary layout elements at any depth
labelGroup label content, used when the `label` prop is not set

CSS parts

Style from outside with c-radio-group::part(name) — parts are the library's only styling customization API.

PartDescription
rootThe radiogroup wrapper element
labelThe group label above the radio buttons
itemsThe container the radios are slotted into
messageThe hint/error message area below the radios (always reserved unless `hide-details`)

<c-radio>

A single radio option inside a `c-radio-group`: a native radio input whose default slot is its clickable, announced label.

Properties

PropertyAttributeTypeDefaultDescription
disableddisabledbooleanfalseDisable the radio button
valuevaluestring''Radio button value

Events

EventDetailDescription
changestringFired when the radio is selected by the user, carrying its `value`. Bubbles composed so the parent `<c-radio-group>` — whose shadow root a light-DOM event never enters — catches it on its host; a consumer listening on the group hears it too, with the radio as `target`.

Slots

SlotDescription
defaultThe radio's label content, rendered inside the shadow `<label>` so it stays click-associated and announced

CSS parts

Style from outside with c-radio::part(name) — parts are the library's only styling customization API.

PartDescription
rootThe `<label>` row wrapping the input, indicator and label content
indicatorThe radio ring itself; the selection dot is its `::after` and the keyboard focus ring its `::before` — all three follow `currentColor`, so `color` recolours the whole indicator, focus ring included
contentWrapper around the slotted label content

Custom states

Select on the host's live state with c-radio:state(name) — combine with ::part() for per-state styling, e.g. c-radio:state(checked)::part(indicator).

StateDescription
checkedPresent while the radio is the selected option (standalone or group-driven)
disabledPresent while the radio is disabled, by its own prop or by its group