Skip to main content

RadioGroup

A radio button group component for single selection from mutually exclusive options with flexible layouts

RadioGroup

The RadioGroup component provides a way to present mutually exclusive options where users can select only one choice. It supports both vertical and horizontal layouts, disabled options, and comprehensive validation with proper fieldset/legend semantics for accessibility.

Basic Radio Groups

Single selection from mutually exclusive options

Payment Method

Choose your preferred payment method

Theme Preference

Select your preferred color theme

Current Selections:

Payment: None selected
Theme: light

API Reference

Props

PropTypeDefaultDescription
namestringrequiredForm field name (shared by all radios)
labelstringrequiredGroup label text (legend)
valuestring''Selected value (bindable)
optionsOption[]requiredArray of radio options
requiredbooleanfalseWhether selection is required
errorstring \| nullnullError message to display
helperstring-Helper text below group
orientation'vertical' \| 'horizontal''vertical'Layout direction

Option Interface

interface Option {
  value: string;        // The value when selected
  label: string;        // Display text for the option
  disabled?: boolean;   // Whether option is selectable
}

Usage Examples

Basic Radio Group

<script>
  import RadioGroup from '$lib/shared/components/forms/RadioGroup.svelte';
  
  let theme = $state('light');
  
  const themeOptions = [
    { value: 'light', label: 'Light Theme' },
    { value: 'dark', label: 'Dark Theme' },
    { value: 'auto', label: 'Auto (System)' }
  ];
</script>

<RadioGroup
  name="theme"
  label="Theme Preference"
  bind:value={theme}
  options={themeOptions}
  helper="Choose your preferred color scheme"
/>

Horizontal Layout

<script>
  import RadioGroup from '$lib/shared/components/forms/RadioGroup.svelte';
  
  let priority = $state('medium');
  
  const priorities = [
    { value: 'low', label: 'Low' },
    { value: 'medium', label: 'Medium' },
    { value: 'high', label: 'High' }
  ];
</script>

<RadioGroup
  name="priority"
  label="Task Priority"
  bind:value={priority}
  options={priorities}
  orientation="horizontal"
  helper="Select priority level"
/>

With Disabled Options

<script>
  import RadioGroup from '$lib/shared/components/forms/RadioGroup.svelte';
  
  let plan = $state('');
  
  const plans = [
    { value: 'free', label: 'Free Plan' },
    { value: 'pro', label: 'Pro Plan' },
    { value: 'enterprise', label: 'Enterprise Plan', disabled: true }
  ];
</script>

<RadioGroup
  name="subscription"
  label="Subscription Plan"
  bind:value={plan}
  options={plans}
  helper="Enterprise plan requires sales consultation"
/>

With Validation

<script>
  import RadioGroup from '$lib/shared/components/forms/RadioGroup.svelte';
  
  let selection = $state('');
  let error = $state(null);
  
  const options = [
    { value: 'yes', label: 'Yes, I agree' },
    { value: 'no', label: 'No, I disagree' }
  ];
  
  function validate() {
    if (!selection) {
      error = 'Please make a selection';
    } else {
      error = null;
    }
  }
</script>

<RadioGroup
  name="agreement"
  label="Do you agree?"
  bind:value={selection}
  {options}
  {error}
  required
  onchange={validate}
/>

Semantic Structure

Fieldset and Legend

RadioGroup uses proper semantic HTML structure:

<fieldset role="radiogroup" aria-required="true">
  <legend class="field-label required">Payment Method</legend>
  
  <div class="radio-options">
    <label>
      <input type="radio" name="payment" value="credit" />
      <span>Credit Card</span>
    </label>
    <!-- More options... -->
  </div>
</fieldset>

This structure provides:

  • Grouping context - Screen readers understand options belong together
  • Accessible labeling - Legend labels the entire group
  • Navigation efficiency - Arrow keys move between options
  • Form semantics - Proper form association

Typography System

The RadioGroup component uses design system typography tokens:

Applied Tokens

/* Legend/Group Label */
--typography-caption-size
--typography-caption-color
--typography-caption-weight

/* Option Labels */
--typography-body-size
--typography-body-color
--typography-body-weight

/* Helper/Error Text */
--typography-caption-size
--typography-muted-color  /* helper */
--error                   /* error state */

Layout Options

Vertical Layout (Default)

  • Space efficient - Stacks options vertically
  • Easy scanning - Natural reading flow
  • Mobile friendly - Works well on narrow screens
  • Accessible - Clear association between options

Horizontal Layout

  • Compact - Saves vertical space
  • Quick comparison - Options side-by-side
  • Responsive - Wraps on smaller screens
  • Visual grouping - Shows options as a set

Styling

Visual Design

  • Custom radio buttons - Styled to match design system
  • Consistent spacing - Uses spacing tokens
  • Focus indicators - Clear focus rings
  • Disabled states - Reduced opacity
  • Error styling - Red accents for invalid state

CSS Classes

  • .form-group - Container fieldset
  • .field-label - Legend styling (with .required modifier)
  • .field-choice-label - Individual option container
  • .field-radio - Radio input styling
  • .option-text - Option label text
  • .field-error-message - Error message display
  • .field-hint - Helper text styling

Layout Classes

/* Vertical layout */
.space-y-3 > * + * {
  margin-top: var(--space-3);
}

/* Horizontal layout */
.flex.gap-6 {
  display: flex;
  gap: var(--space-6);
  flex-wrap: wrap;
}

Accessibility

ARIA Support

  • role="radiogroup" - Identifies the group
  • aria-required - Indicates required groups
  • aria-invalid - Communicates error states
  • aria-describedby - Links helper and error text
  • role="alert" - Error messages announced

Keyboard Interaction

  • Tab - Navigate to radio group
  • Arrow keys - Move between options within group
  • Space - Select focused option
  • Tab - Leave group (continues to next form field)

Screen Reader Support

  • Legend announced when entering group
  • Current selection status communicated
  • Error messages read via live regions
  • Option count and position announced

Validation Patterns

Required Selection

<script>
  let value = $state('');
  let error = $state(null);
  
  function handleSubmit() {
    if (!value) {
      error = 'Please make a selection';
      return false;
    }
    return true;
  }
</script>

<RadioGroup
  name="required-field"
  label="Required Choice"
  bind:value
  {options}
  {error}
  required
/>

Conditional Validation

<script>
  let paymentMethod = $state('');
  let cardType = $state('');
  let cardError = $state(null);
  
  $effect(() => {
    if (paymentMethod === 'card' && !cardType) {
      cardError = 'Please select card type';
    } else {
      cardError = null;
    }
  });
</script>

Best Practices

When to Use Radio Groups

Use radio buttons when:

  • Mutually exclusive choices - Only one option can be selected
  • Visible options - All choices should be visible
  • Small sets - 2-7 options work best
  • Quick selection - Users need to compare options

Content Guidelines

  1. Clear labels - Each option should be descriptive
  2. Parallel structure - Use consistent phrasing
  3. Logical order - Arrange by frequency or importance
  4. Avoid negatives - Prefer positive phrasing

Layout Decisions

  1. Vertical for content - When options have different lengths
  2. Horizontal for UI - For short, similar-length options
  3. Group related options - Use visual grouping or spacing
  4. Consider mobile - Test touch targets and readability

Error Handling

  1. Clear messaging - Explain what selection is needed
  2. Contextual errors - Show errors near the group
  3. Preserve selection - Don’t reset on validation errors
  4. Recovery guidance - Help users fix the issue

Common Use Cases

Settings and Preferences

  • Theme selection (light/dark/auto)
  • Notification frequency
  • Privacy levels
  • Language selection

Forms and Surveys

  • Multiple choice questions
  • Rating scales
  • Yes/No/Maybe responses
  • Demographic information

E-commerce

  • Shipping methods
  • Payment options
  • Product variants (size, color)
  • Subscription plans

Configuration

  • Feature toggles
  • Permission levels
  • View modes
  • Sort orders

RadioGroup vs Other Components

vs Checkbox

  • Radio: Single selection, mutually exclusive
  • Checkbox: Multiple selections, independent choices

vs Select Dropdown

  • Radio: All options visible, quick comparison
  • Select: Space-efficient, many options supported

vs Toggle

  • Radio: Multiple options, permanent choice
  • Toggle: Binary choice, immediate effect