Skip to main content

Overview

The Radio component provides accessible radio buttons with RadioGroup for managing selections. Supports multiple sizes, orientations, and descriptions. Built on React Aria Components for full keyboard navigation and screen reader support.

Import

import { Radio, RadioGroup } from 'stride-ds';

Basic Usage

import { Radio, RadioGroup } from 'stride-ds';

function Example() {
  return (
    <RadioGroup label="Choose your preferred option">
      <Radio value="option1">Option 1</Radio>
      <Radio value="option2">Option 2</Radio>
      <Radio value="option3">Option 3</Radio>
    </RadioGroup>
  );
}

Orientation

Vertical (Default)

<RadioGroup label="Select size" orientation="vertical">
  <Radio value="small">Small</Radio>
  <Radio value="medium">Medium</Radio>
  <Radio value="large">Large</Radio>
</RadioGroup>

Horizontal

<RadioGroup label="Select size" orientation="horizontal">
  <Radio value="small">Small</Radio>
  <Radio value="medium">Medium</Radio>
  <Radio value="large">Large</Radio>
</RadioGroup>

Sizes

Three size options are available:
<RadioGroup label="Small Size" size="sm">
  <Radio value="sm1" size="sm">Small Option 1</Radio>
  <Radio value="sm2" size="sm">Small Option 2</Radio>
</RadioGroup>

<RadioGroup label="Medium Size" size="md">
  <Radio value="md1" size="md">Medium Option 1</Radio>
  <Radio value="md2" size="md">Medium Option 2</Radio>
</RadioGroup>

<RadioGroup label="Large Size" size="lg">
  <Radio value="lg1" size="lg">Large Option 1</Radio>
  <Radio value="lg2" size="lg">Large Option 2</Radio>
</RadioGroup>

With Descriptions

Add supporting text to radio options:
<RadioGroup 
  label="Choose your plan"
  description="Select the plan that best fits your needs"
>
  <Radio value="basic" description="Perfect for getting started">
    Basic Plan
  </Radio>
  <Radio value="pro" description="Great for growing businesses">
    Pro Plan
  </Radio>
  <Radio value="enterprise" description="Advanced features for large teams">
    Enterprise Plan
  </Radio>
</RadioGroup>

States

Default Value

<RadioGroup label="Choose option" defaultValue="option1">
  <Radio value="option1">Selected by default</Radio>
  <Radio value="option2">Option 2</Radio>
</RadioGroup>

Disabled

<RadioGroup label="Disabled Group" isDisabled defaultValue="option1">
  <Radio value="option1">Disabled Selected</Radio>
  <Radio value="option2">Disabled Unselected</Radio>
</RadioGroup>

Required

<RadioGroup label="Required Field" isRequired>
  <Radio value="option1">Option 1</Radio>
  <Radio value="option2">Option 2</Radio>
</RadioGroup>

With Error

<RadioGroup 
  label="Choose your preference"
  errorMessage="Please select an option"
  isInvalid
>
  <Radio value="option1">Option 1</Radio>
  <Radio value="option2">Option 2</Radio>
</RadioGroup>

RadioGroup Props

label
React.ReactNode
Label for the radio group.
description
React.ReactNode
Description text displayed below the label.
errorMessage
React.ReactNode
Error message displayed when isInvalid is true.
orientation
'horizontal' | 'vertical'
default:"'vertical'"
Layout direction of the radio buttons.
size
'sm' | 'md' | 'lg'
default:"'md'"
Size of the radio buttons in the group.
value
string
The currently selected value (controlled).
defaultValue
string
The initially selected value (uncontrolled).
onChange
(value: string) => void
Handler called when the selection changes.
isDisabled
boolean
default:"false"
Whether the entire radio group is disabled.
isRequired
boolean
default:"false"
Whether a selection is required.
isInvalid
boolean
default:"false"
Whether the radio group is in an invalid state.
className
string
Additional CSS classes to apply.

Radio Props

value
string
required
The value of this radio button.
children
React.ReactNode
The label text for the radio button.
description
React.ReactNode
Additional description text displayed below the label.
size
'sm' | 'md' | 'lg'
default:"'md'"
Size of the radio button. Inherits from RadioGroup if not specified.
isDisabled
boolean
default:"false"
Whether this specific radio button is disabled.
className
string
Additional CSS classes to apply.

Accessibility

The Radio components are built with React Aria Components and provide:
  • Keyboard Navigation: Arrow keys to navigate between options, Space to select
  • Focus Management: Proper focus handling and roving tabindex
  • Screen Reader Support: Proper ARIA attributes and role=“radiogroup”
  • Group Labeling: Automatic association between group label and radios
  • Required/Invalid States: Properly announced to assistive technologies

Best Practices

  1. Always provide a label for the RadioGroup:
    <RadioGroup label="Choose an option">
      {/* radios */}
    </RadioGroup>
    
  2. Use meaningful value attributes:
    <Radio value="small">Small</Radio>
    <Radio value="medium">Medium</Radio>
    
  3. Add descriptions for complex choices:
    <Radio value="pro" description="Includes all features">
      Pro Plan
    </Radio>
    

Examples

Subscription Plan Selector

import { RadioGroup, Radio } from 'stride-ds';

function PlanSelector() {
  return (
    <RadioGroup
      label="Subscription Plan"
      description="Choose the plan that works best for you"
      defaultValue="pro"
    >
      <Radio value="free" description="Free forever with basic features">
        Free Plan - $0/month
      </Radio>
      <Radio value="pro" description="Everything in Free plus advanced analytics">
        Pro Plan - $19/month
      </Radio>
      <Radio value="enterprise" description="Everything in Pro plus priority support">
        Enterprise - $99/month
      </Radio>
    </RadioGroup>
  );
}

Horizontal Button Group

<RadioGroup 
  label="Size" 
  orientation="horizontal"
  defaultValue="medium"
>
  <Radio value="small">S</Radio>
  <Radio value="medium">M</Radio>
  <Radio value="large">L</Radio>
  <Radio value="xlarge">XL</Radio>
</RadioGroup>

All States

<div className="space-y-8">
  <RadioGroup label="Default State" defaultValue="option1">
    <Radio value="option1">Selected Option</Radio>
    <Radio value="option2">Unselected Option</Radio>
  </RadioGroup>

  <RadioGroup label="Disabled State" isDisabled defaultValue="disabled1">
    <Radio value="disabled1">Disabled Selected</Radio>
    <Radio value="disabled2">Disabled Unselected</Radio>
  </RadioGroup>

  <RadioGroup label="Required Field" isRequired>
    <Radio value="req1">Required Option 1</Radio>
    <Radio value="req2">Required Option 2</Radio>
  </RadioGroup>

  <RadioGroup 
    label="With Error" 
    isInvalid
    errorMessage="Please select an option"
  >
    <Radio value="err1">Option 1</Radio>
    <Radio value="err2">Option 2</Radio>
  </RadioGroup>
</div>

Controlled Component

import { useState } from 'react';
import { RadioGroup, Radio } from 'stride-ds';

function ControlledExample() {
  const [selected, setSelected] = useState('option1');

  return (
    <div>
      <RadioGroup 
        label="Controlled Radio Group" 
        value={selected}
        onChange={setSelected}
      >
        <Radio value="option1">Option 1</Radio>
        <Radio value="option2">Option 2</Radio>
        <Radio value="option3">Option 3</Radio>
      </RadioGroup>
      
      <p className="mt-4">Selected: {selected}</p>
    </div>
  );
}

React Hook Form Integration

The Radio components work with React Hook Form:
import { useForm, Controller } from 'react-hook-form';
import { RadioGroup, Radio } from 'stride-ds';

function FormExample() {
  const { control, handleSubmit, formState: { errors } } = useForm();

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        name="plan"
        control={control}
        rules={{ required: 'Please select a plan' }}
        render={({ field }) => (
          <RadioGroup
            label="Choose a plan"
            value={field.value}
            onChange={field.onChange}
            isInvalid={!!errors.plan}
            errorMessage={errors.plan?.message}
          >
            <Radio value="free">Free</Radio>
            <Radio value="pro">Pro</Radio>
            <Radio value="enterprise">Enterprise</Radio>
          </RadioGroup>
        )}
      />
    </form>
  );
}

Build docs developers (and LLMs) love