# Radio Group Component Usage
## Overview
The radio group component provides accessible radio buttons for single selection from a list of options. It supports various layouts including vertical lists, horizontal groups, and card-style selections. Radio groups are built using native HTML radio inputs with enhanced styling.
## JavaScript Requirements
### Required Scripts
```html
<!-- Include Basecoat CSS and JavaScript -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/basecoat-css@latest/dist/basecoat.cdn.min.css">
<script src="https://cdn.jsdelivr.net/npm/basecoat-css@latest/dist/js/basecoat.min.js" defer></script>
<script src="https://cdn.jsdelivr.net/npm/basecoat-css@latest/dist/js/radio-group.min.js" defer></script>
```
## HTML Structure
### Basic Radio Group
```html
<fieldset class="radio-group grid gap-3" role="radiogroup">
<legend class="label mb-2">Select an option</legend>
<label class="label gap-3">
<input type="radio" name="option" value="option1" checked>
Option 1
</label>
<label class="label gap-3">
<input type="radio" name="option" value="option2">
Option 2
</label>
<label class="label gap-3">
<input type="radio" name="option" value="option3">
Option 3
</label>
</fieldset>
```
### Radio with Description
```html
<fieldset class="radio-group grid gap-4" role="radiogroup">
<legend class="label mb-2">Notification frequency</legend>
<div class="flex items-start gap-3">
<input type="radio" id="instant" name="frequency" value="instant" class="mt-1">
<div class="grid gap-1">
<label for="instant" class="label">Instant</label>
<p class="text-muted-foreground text-sm">Get notified immediately for all activity</p>
</div>
</div>
<div class="flex items-start gap-3">
<input type="radio" id="daily" name="frequency" value="daily" class="mt-1">
<div class="grid gap-1">
<label for="daily" class="label">Daily Digest</label>
<p class="text-muted-foreground text-sm">Receive a summary once per day</p>
</div>
</div>
<div class="flex items-start gap-3">
<input type="radio" id="weekly" name="frequency" value="weekly" class="mt-1">
<div class="grid gap-1">
<label for="weekly" class="label">Weekly Digest</label>
<p class="text-muted-foreground text-sm">Receive a summary once per week</p>
</div>
</div>
</fieldset>
```
## States
### Default State
```html
<input type="radio" name="option" value="default">
```
### Selected State
```html
<input type="radio" name="option" value="selected" checked>
```
### Disabled State
```html
<input type="radio" name="option" value="disabled" disabled>
<input type="radio" name="option" value="disabled-checked" checked disabled>
```
### Invalid State
```html
<input type="radio" name="option" value="invalid" aria-invalid="true">
```
## Implementation Examples
### Plan Selection
```html
<form class="form space-y-6">
<fieldset class="radio-group grid gap-4" role="radiogroup">
<legend class="text-lg font-medium mb-2">Choose a plan</legend>
<label class="flex items-start gap-3 p-4 border rounded-lg cursor-pointer hover:bg-accent/50 has-[:checked]:border-primary has-[:checked]:bg-primary/5">
<input type="radio" name="plan" value="free" class="mt-1">
<div class="grid gap-1 flex-1">
<div class="flex items-center justify-between">
<span class="font-medium">Free</span>
<span class="text-muted-foreground">$0/month</span>
</div>
<p class="text-muted-foreground text-sm">Perfect for trying out our service</p>
</div>
</label>
<label class="flex items-start gap-3 p-4 border rounded-lg cursor-pointer hover:bg-accent/50 has-[:checked]:border-primary has-[:checked]:bg-primary/5">
<input type="radio" name="plan" value="pro" class="mt-1" checked>
<div class="grid gap-1 flex-1">
<div class="flex items-center justify-between">
<span class="font-medium">Pro</span>
<span class="text-muted-foreground">$29/month</span>
</div>
<p class="text-muted-foreground text-sm">Best for professionals and small teams</p>
</div>
</label>
<label class="flex items-start gap-3 p-4 border rounded-lg cursor-pointer hover:bg-accent/50 has-[:checked]:border-primary has-[:checked]:bg-primary/5">
<input type="radio" name="plan" value="enterprise" class="mt-1">
<div class="grid gap-1 flex-1">
<div class="flex items-center justify-between">
<span class="font-medium">Enterprise</span>
<span class="text-muted-foreground">Custom</span>
</div>
<p class="text-muted-foreground text-sm">For large organizations with custom needs</p>
</div>
</label>
</fieldset>
<button type="submit" class="btn">Continue</button>
</form>
```
### Shipping Options
```html
<fieldset class="radio-group grid gap-3" role="radiogroup">
<legend class="label mb-2">Shipping Method</legend>
<label class="flex items-center justify-between p-3 border rounded-lg cursor-pointer hover:bg-accent/50 has-[:checked]:border-primary">
<div class="flex items-center gap-3">
<input type="radio" name="shipping" value="standard">
<div>
<span class="font-medium">Standard Shipping</span>
<p class="text-muted-foreground text-sm">5-7 business days</p>
</div>
</div>
<span class="font-medium">$4.99</span>
</label>
<label class="flex items-center justify-between p-3 border rounded-lg cursor-pointer hover:bg-accent/50 has-[:checked]:border-primary">
<div class="flex items-center gap-3">
<input type="radio" name="shipping" value="express" checked>
<div>
<span class="font-medium">Express Shipping</span>
<p class="text-muted-foreground text-sm">2-3 business days</p>
</div>
</div>
<span class="font-medium">$9.99</span>
</label>
<label class="flex items-center justify-between p-3 border rounded-lg cursor-pointer hover:bg-accent/50 has-[:checked]:border-primary">
<div class="flex items-center gap-3">
<input type="radio" name="shipping" value="overnight">
<div>
<span class="font-medium">Overnight Shipping</span>
<p class="text-muted-foreground text-sm">Next business day</p>
</div>
</div>
<span class="font-medium">$19.99</span>
</label>
</fieldset>
```
### Horizontal Radio Group
```html
<fieldset class="radio-group" role="radiogroup">
<legend class="label mb-3">Size</legend>
<div class="flex gap-3">
<label class="label gap-2">
<input type="radio" name="size" value="small">
Small
</label>
<label class="label gap-2">
<input type="radio" name="size" value="medium" checked>
Medium
</label>
<label class="label gap-2">
<input type="radio" name="size" value="large">
Large
</label>
</div>
</fieldset>
```
### Rating Selection
```html
<fieldset class="radio-group" role="radiogroup" aria-label="Rating">
<legend class="label mb-3">How would you rate your experience?</legend>
<div class="flex gap-2">
<label class="flex flex-col items-center gap-1 cursor-pointer">
<input type="radio" name="rating" value="1" class="sr-only peer">
<span class="text-2xl peer-checked:scale-110 transition-transform">😞</span>
<span class="text-xs text-muted-foreground">Poor</span>
</label>
<label class="flex flex-col items-center gap-1 cursor-pointer">
<input type="radio" name="rating" value="2" class="sr-only peer">
<span class="text-2xl peer-checked:scale-110 transition-transform">😐</span>
<span class="text-xs text-muted-foreground">Fair</span>
</label>
<label class="flex flex-col items-center gap-1 cursor-pointer">
<input type="radio" name="rating" value="3" class="sr-only peer">
<span class="text-2xl peer-checked:scale-110 transition-transform">🙂</span>
<span class="text-xs text-muted-foreground">Good</span>
</label>
<label class="flex flex-col items-center gap-1 cursor-pointer">
<input type="radio" name="rating" value="4" class="sr-only peer">
<span class="text-2xl peer-checked:scale-110 transition-transform">😊</span>
<span class="text-xs text-muted-foreground">Great</span>
</label>
<label class="flex flex-col items-center gap-1 cursor-pointer">
<input type="radio" name="rating" value="5" class="sr-only peer">
<span class="text-2xl peer-checked:scale-110 transition-transform">🤩</span>
<span class="text-xs text-muted-foreground">Excellent</span>
</label>
</div>
</fieldset>
```
## JavaScript Events
### Initialization Event
```javascript
document.addEventListener('basecoat:initialized', function(e) {
if (e.target.matches('.radio-group')) {
console.log('Radio group initialized');
}
});
```
### Change Event Handling
```javascript
const radioGroup = document.querySelectorAll('input[name="plan"]');
radioGroup.forEach(radio => {
radio.addEventListener('change', function() {
if (this.checked) {
console.log('Selected plan:', this.value);
updatePriceDisplay(this.value);
}
});
});
function updatePriceDisplay(plan) {
const prices = { free: 0, pro: 29, enterprise: 'Custom' };
document.getElementById('price-display').textContent =
typeof prices[plan] === 'number' ? `$${prices[plan]}/month` : prices[plan];
}
```
### Programmatic Selection
```javascript
function selectRadio(name, value) {
const radio = document.querySelector(`input[name="${name}"][value="${value}"]`);
if (radio) {
radio.checked = true;
radio.dispatchEvent(new Event('change', { bubbles: true }));
}
}
// Usage
selectRadio('plan', 'pro');
```
## Accessibility Guidelines
### ARIA Requirements
- Use `role="radiogroup"` on the container
- Provide a `<legend>` or `aria-label` for the group
- Each radio should have an associated label
- Use `aria-describedby` for additional descriptions
### Example with Full Accessibility
```html
<fieldset
class="radio-group grid gap-3"
role="radiogroup"
aria-labelledby="payment-legend"
aria-describedby="payment-desc"
>
<legend id="payment-legend" class="label mb-1">Payment Method</legend>
<p id="payment-desc" class="text-muted-foreground text-sm mb-3">
Select your preferred payment method
</p>
<div class="flex items-start gap-3">
<input
type="radio"
id="credit-card"
name="payment"
value="credit-card"
aria-describedby="credit-desc"
class="mt-1"
>
<div class="grid gap-1">
<label for="credit-card" class="label">Credit Card</label>
<p id="credit-desc" class="text-muted-foreground text-sm">
Visa, Mastercard, American Express
</p>
</div>
</div>
<div class="flex items-start gap-3">
<input
type="radio"
id="paypal"
name="payment"
value="paypal"
aria-describedby="paypal-desc"
class="mt-1"
>
<div class="grid gap-1">
<label for="paypal" class="label">PayPal</label>
<p id="paypal-desc" class="text-muted-foreground text-sm">
Pay securely with your PayPal account
</p>
</div>
</div>
</fieldset>
```
### Keyboard Navigation
- **Arrow Up/Down**: Move between radio options (vertical layout)
- **Arrow Left/Right**: Move between radio options (horizontal layout)
- **Space**: Select the focused option
- **Tab**: Move focus to/from the radio group
## Best Practices
### When to Use Radio Groups
- Single selection from 2-7 options
- When all options need to be visible
- When comparison between options is important
- Mutually exclusive choices
### When to Use Other Components
- Many options (7+): Use Select/Combobox instead
- On/Off binary: Use Switch instead
- Multiple selections: Use Checkboxes instead
### Visual Guidelines
- Display all options at once when possible
- Use consistent spacing between options
- Clearly indicate the selected state
- Group related options logically
### Label Guidelines
- Keep option labels concise
- Use parallel grammatical structure
- Order options logically (alphabetically, by frequency, etc.)
- Include additional context with descriptions when needed
## Form Integration
### Using with Form Class
```html
<form class="form grid gap-6">
<fieldset class="radio-group grid gap-3" role="radiogroup">
<legend class="label mb-2">Preferred contact method</legend>
<label class="label gap-3">
<input type="radio" name="contact" value="email" required>
Email
</label>
<label class="label gap-3">
<input type="radio" name="contact" value="phone">
Phone
</label>
<label class="label gap-3">
<input type="radio" name="contact" value="text">
Text Message
</label>
</fieldset>
<button type="submit" class="btn">Submit</button>
</form>
```
### Validation
```javascript
const form = document.querySelector('form');
form.addEventListener('submit', function(e) {
const selected = document.querySelector('input[name="contact"]:checked');
if (!selected) {
e.preventDefault();
// Show error
const fieldset = document.querySelector('.radio-group');
fieldset.setAttribute('aria-invalid', 'true');
// Display error message
}
});
```