Skip to content

SuRadioGroup

SuRadioGroup component for single selection with two display styles: classic or cards. Complete accessibility support according to W3C standards.

Usage examples

Basic SuRadioGroup

Default style

vue
<script setup>
const selectedValue = ref('')
const options = [
  { value: 'option1', label: 'Option 1' },
  { value: 'option2', label: 'Option 2' },
  { value: 'option3', label: 'Option 3' },
  { value: 'option4', label: 'Option 4', disabled: true }
]
</script>

<template>
  <SuRadioGroupField 
    :options="options"
    label="Single selection"
    name="basic-radio"
    v-model="selectedValue"
  />
</template>

Card style

Block cards

vue
<template>
  <SuRadioGroupField 
    :options="[
      { 
        value: 'basic', 
        label: 'Basic Plan', 
        description: 'Basic features to get started'
      },
      { 
        value: 'pro', 
        label: 'Pro Plan', 
        description: 'Advanced features for professionals'
      },
      { 
        value: 'enterprise', 
        label: 'Enterprise Plan', 
        description: 'Complete solution for large companies'
      }
    ]"
    displayType="block-card"
    label="Subscription plan"
    name="plan-radio"
    v-model="selectedPlan"
  />
</template>

Inline cards

Inline cards

vue
<template>
  <SuRadioGroupField 
    :options="[
      { value: 'small', label: 'Small', description: 'Up to 5 users' },
      { value: 'medium', label: 'Medium', description: 'Up to 25 users' },
      { value: 'large', label: 'Large', description: 'Unlimited users' }
    ]"
    displayType="inline-card"
    direction="horizontal"
    label="Team size"
    name="team-size-radio"
    v-model="teamSize"
  />
</template>

With icons

Options with icons

vue
<script setup>
import { UserIcon, BuildingOfficeIcon, GlobeAltIcon } from '@heroicons/vue/24/outline'

const accountType = ref('')
const accountOptions = [
  { value: 'user', label: 'Individual', icon: UserIcon },
  { value: 'business', label: 'Business', icon: BuildingOfficeIcon },
  { value: 'organization', label: 'Organization', icon: GlobeAltIcon }
]
</script>

<template>
  <SuRadioGroupField 
    :options="accountOptions"
    displayType="block-card"
    label="Account type"
    name="account-type-radio"
    v-model="accountType"
  />
</template>

API

Props

PropTypeDefaultDescription
optionsRadioOption[][]List of radio options
valuestring | numberundefinedSelected value
namestringundefinedRadio group name (auto-generated if not provided)
size'sm' | 'md' | 'lg''md'Element size
state'default' | 'error' | 'success' | 'warning''default'Visual state
disabledbooleanfalseDisable the entire group
requiredbooleanfalseRequired field
displayType'default' | 'inline-card' | 'block-card''default'Display type
direction'horizontal' | 'vertical''vertical'Group direction
maxHeightstringnullMaximum height with automatic scroll
labelstringundefinedGroup label
messagestringundefinedDisplayed message

Option types

RadioOption

typescript
interface RadioOption {
  value: string | number
  label: string
  description?: string
  disabled?: boolean
  icon?: Component
}

Events

EventTypeDescription
@update:value(value: string | number) => voidEmitted when value changes
@change(value: string | number) => voidEmitted on change
@focus(event: FocusEvent) => voidEmitted on focus
@blur(event: FocusEvent) => voidEmitted on blur

Accessibility

The RadioGroup component follows WCAG 2.1 AA standards:

✅ Accessibility features

  • Fieldset and Legend: Correct semantic structure with <fieldset> and <legend>
  • ARIA attributes: role="radiogroup", aria-required, aria-invalid
  • Keyboard navigation: Support for arrow keys, Tab, Space
  • Associated labels: Each radio has a properly associated label
  • State messages: Messages with aria-live for screen readers
  • Visible focus: Clear and contrasted focus indicators
  • Color contrast: WCAG AA compliant ratios
  • Logical grouping: Options semantically grouped

🎯 Best practices

vue
<!-- RadioGroup with validation -->
<SuRadioGroupField 
  :options="options"
  :required="true"
  label="Payment method"
  name="payment-method"
  :state="hasError ? 'error' : 'default'"
  :message="hasError ? 'Please select a payment method' : undefined"
  v-model="paymentMethod"
/>

<!-- RadioGroup with cards and descriptions -->
<SuRadioGroupField 
  :options="planOptions"
  displayType="block-card"
  label="Subscription plan"
  name="subscription-plan"
  message="Choose the plan that fits your needs"
  v-model="selectedPlan"
/>

Keyboard navigation

KeyAction
TabNavigate to/from group
ArrowsNavigate between group options
SpaceSelect focused option

Advanced usage examples

Configuration form

vue
<script setup>
import { ref } from 'vue'
import { CogIcon, UserIcon, ShieldCheckIcon } from '@heroicons/vue/24/outline'

const theme = ref('light')
const privacy = ref('public')

const themeOptions = [
  { value: 'light', label: 'Light', description: 'Light interface' },
  { value: 'dark', label: 'Dark', description: 'Dark interface' },
  { value: 'auto', label: 'Auto', description: 'Follow system preferences' }
]

const privacyOptions = [
  { value: 'public', label: 'Public', icon: UserIcon },
  { value: 'private', label: 'Private', icon: ShieldCheckIcon }
]
</script>

<template>
  <form class="space-y-6">
    <SuRadioGroupField 
      :options="themeOptions"
      displayType="block-card"
      label="Theme"
      name="theme"
      v-model="theme"
    />
    
    <SuRadioGroupField 
      :options="privacyOptions"
      displayType="inline-card"
      direction="horizontal"
      label="Privacy"
      name="privacy"
      v-model="privacy"
    />
  </form>
</template>

Publié sous licence MIT.