Radio Group
A group of radio buttons for single selection from multiple options
Basic Usage
Simple radio group with basic options.
1
2<script lang="ts">
3 import { RadioGroup, RadioGroupPrimitives } from "@kareyes/aether";
4
5 type RadioGroupOption = RadioGroupPrimitives.RadioGroupOption;
6 let themeSelection = $state("auto");
7
8 const basicOptions: RadioGroupOption[] = [
9 { id: "1", label: "Option 1", value: "option1" },
10 { id: "2", label: "Option 2", value: "option2" },
11 { id: "3", label: "Option 3", value: "option3" },
12 ];
13
14 const themeOptions: RadioGroupOption[] = [
15 { id: "light", label: "Light", value: "light" },
16 { id: "dark", label: "Dark", value: "dark" },
17 { id: "auto", label: "Auto", value: "auto" },
18 ];
19</script>
20
21<div class="grid gap-8 md:grid-cols-2">
22 <RadioGroup
23 options={basicOptions}
24 bind:value={themeSelection}
25 label="Choose an option"
26 description="Select one option from the list"
27 />
28
29 <RadioGroup
30 options={themeOptions}
31 bind:value={themeSelection}
32 label="Theme Selection"
33 description="Choose your preferred theme"
34 onValueChange={(val) => console.log('Theme changed:', val)}
35 />
36</div>With Descriptions
Radio options with descriptive text for additional context.
1
2<script lang="ts">
3 import { RadioGroup, RadioGroupPrimitives } from "@kareyes/aether";
4 type RadioGroupOption = RadioGroupPrimitives.RadioGroupOption;
5
6 let selectedPlan = $state("pro");
7 let notificationPreference = $state("email");
8
9 const planOptions: RadioGroupOption[] = [
10 { id: "free", label: "Free", value: "free", description: "$0/month - Basic features" },
11 { id: "pro", label: "Pro", value: "pro", description: "$29/month - Advanced features" },
12 { id: "enterprise", label: "Enterprise", value: "enterprise", description: "$99/month - Full features" },
13 ];
14
15 const notificationOptions: RadioGroupOption[] = [
16 { id: "email", label: "Email", value: "email", description: "Receive notifications via email" },
17 { id: "sms", label: "SMS", value: "sms", description: "Receive notifications via text message" },
18 { id: "push", label: "Push", value: "push", description: "Receive push notifications" },
19 { id: "none", label: "None", value: "none", description: "Don't receive notifications", disabled: true },
20 ];
21</script>
22
23<div class="grid gap-8 md:grid-cols-2">
24 <RadioGroup
25 options={planOptions}
26 bind:value={selectedPlan}
27 label="Subscription Plan"
28 description="Select your pricing tier"
29 radioSize="lg"
30 />
31
32 <RadioGroup
33 options={notificationOptions}
34 bind:value={notificationPreference}
35 label="Notification Preferences"
36 description="How would you like to be notified?"
37 />
38</div>Orientations
Vertical and horizontal layout options.
Vertical (Default)
Horizontal
1
2<RadioGroup
3 options={basicOptions}
4 bind:value={themeSelection}
5 orientation="vertical"
6 label="Vertical Layout"
7/>
8
9<RadioGroup
10 options={themeOptions}
11 bind:value={themeSelection}
12 orientation="horizontal"
13 label="Horizontal Layout"
14/>Sizes
Available radio button size options.
1
2<div class="grid gap-8 md:grid-cols-3">
3 <RadioGroup
4 options={basicOptions.slice(0, 2)}
5 value="option1"
6 radioSize="sm"
7 label="Small Radio"
8 />
9
10 <RadioGroup
11 options={basicOptions.slice(0, 2)}
12 value="option1"
13 radioSize="default"
14 label="Default Radio"
15 />
16
17 <RadioGroup
18 options={basicOptions.slice(0, 2)}
19 value="option1"
20 radioSize="lg"
21 label="Large Radio"
22 />
23</div>Variants
Color variants for different semantic meanings.
1
2<div class="grid gap-8 md:grid-cols-2">
3 <RadioGroup options={basicOptions} value="option1" variant="default" label="Default Variant" />
4 <RadioGroup options={basicOptions} value="option1" variant="destructive" label="Destructive Variant" />
5 <RadioGroup options={basicOptions} value="option1" variant="success" label="Success Variant" />
6 <RadioGroup options={basicOptions} value="option1" variant="warning" label="Warning Variant" />
7</div>Error States
Validation error display with radio groups.
1
2<script lang="ts">
3 import { RadioGroup, RadioGroupPrimitives } from "@kareyes/aether";
4 type RadioGroupOption = RadioGroupPrimitives.RadioGroupOption;
5
6 let errorSelection = $state("");
7</script>
8
9<div class="grid gap-8 md:grid-cols-2">
10 <RadioGroup
11 options={basicOptions}
12 bind:value={errorSelection}
13 label="Required Selection"
14 description="Please select an option"
15 error={!errorSelection}
16 required
17 />
18
19 <RadioGroup
20 options={planOptions}
21 value=""
22 label="Plan Selection (Error)"
23 description="Selection required"
24 error={true}
25 radioSize="lg"
26 />
27</div>With Field Component
Using the Field component for labels, descriptions, and error handling.
Select the plan that fits your needs
How would you like to be notified?
Selected Plan: pro
Notification: email
1
2<script lang="ts">
3 import { RadioGroup, Field, Badge } from "@kareyes/aether";
4</script>
5
6<div class="grid gap-8 md:grid-cols-2">
7 <Field
8 label="Choose Your Plan"
9 description="Select the plan that fits your needs"
10 required
11 >
12 <RadioGroup options={planOptions} bind:value={selectedPlan} />
13 </Field>
14
15 <Field
16 label="Notification Preference"
17 description="How would you like to be notified?"
18 error={!notificationPreference ? "Please select a notification method" : undefined}
19 >
20 <RadioGroup
21 options={notificationOptions}
22 bind:value={notificationPreference}
23 error={!notificationPreference}
24 />
25 </Field>
26</div>
27
28<div class="space-y-2">
29 <p class="text-sm text-muted-foreground">
30 Selected Plan: <Badge variant="secondary">{selectedPlan}</Badge>
31 </p>
32 <p class="text-sm text-muted-foreground">
33 Notification: <Badge variant="outline">{notificationPreference}</Badge>
34 </p>
35</div>Interactive Examples
Live interactive radio group demos.
Theme Selection
Current theme: auto
1
2<script lang="ts">
3 import { RadioGroup, Badge } from "@kareyes/aether";
4 let themeSelection = $state("auto");
5</script>
6
7<div class="space-y-4">
8 <h3 class="text-lg font-medium">Theme Selection</h3>
9 <p class="text-sm text-muted-foreground">
10 Current theme: <Badge variant="outline">{themeSelection}</Badge>
11 </p>
12 <RadioGroup
13 options={themeOptions}
14 bind:value={themeSelection}
15 orientation="horizontal"
16 />
17</div>Disabled State
Radio group in disabled state.
1
2<RadioGroup
3 options={basicOptions}
4 value="option2"
5 label="Disabled Radio Group"
6 description="This group is disabled"
7 disabled
8/>Card Style
Use the card style for more prominent selections with clickable cards.
Cluster Type Selection
Selected: kubernetes
Subscription Plans (Card Style)
Selected: pro
1
2<script lang="ts">
3 import { RadioGroup, Badge, RadioGroupPrimitives } from "@kareyes/aether";
4 type RadioGroupOption = RadioGroupPrimitives.RadioGroupOption;
5
6 let clusterType = $state("kubernetes");
7
8 const clusterOptions: RadioGroupOption[] = [
9 { id: "kubernetes", label: "Kubernetes", value: "kubernetes", description: "Run GPU workloads on a K8s configured cluster." },
10 { id: "vm", label: "Virtual Machine", value: "vm", description: "Access a VM configured cluster to run GPU workloads." },
11 ];
12</script>
13
14<RadioGroup
15 options={clusterOptions}
16 bind:value={clusterType}
17 label="Select Cluster Type"
18 description="Choose how you want to run your workloads"
19 isCard={true}
20 radioSize="lg"
21/>
22<p class="text-sm text-muted-foreground">
23 Selected: <Badge variant="secondary">{clusterType}</Badge>
24</p>Card Style vs Regular
Comparison between card style and regular radio group layouts.
Regular Style
Card Style
1
2<div class="grid gap-8 md:grid-cols-2">
3 <div>
4 <h3 class="text-lg font-medium mb-4">Regular Style</h3>
5 <RadioGroup
6 options={clusterOptions}
7 value="kubernetes"
8 label="Cluster Type"
9 description="Regular radio button layout"
10 isCard={false}
11 />
12 </div>
13
14 <div>
15 <h3 class="text-lg font-medium mb-4">Card Style</h3>
16 <RadioGroup
17 options={clusterOptions}
18 value="kubernetes"
19 label="Cluster Type"
20 description="Card-based layout (clickable cards)"
21 isCard={true}
22 />
23 </div>
24</div>Card Style with Variants
Card-style radio groups with color variants.
1
2<div class="grid gap-8 md:grid-cols-2">
3 <RadioGroup
4 options={cardPlanOptions.slice(0, 2)}
5 value="pro"
6 label="Success Variant"
7 isCard={true}
8 variant="success"
9 />
10
11 <RadioGroup
12 options={[
13 { id: "soft-del", label: "Soft Delete", value: "soft", description: "Move items to trash (recoverable)" },
14 { id: "perm-del", label: "Permanent Delete", value: "permanent", description: "Delete permanently (cannot be undone)" },
15 ]}
16 value="soft"
17 label="Warning Variant"
18 isCard={true}
19 variant="warning"
20 />
21</div>Features
- Options Pattern: Data-driven approach with options array
- Card Style UI: Optional card-style layout with clickable cards (
isCardprop) - Variants: Multiple visual styles (default, destructive, success, warning)
- Sizes: Three size options (sm, default, lg)
- Flexible Layout: Supports vertical and horizontal arrangements
- Error Handling: Built-in error state with visual feedback
- Field Integration: Works seamlessly with Field component
- Accessibility: Full keyboard navigation and screen reader support
- TypeScript: Complete type safety with exported types
- Responsive: Adapts to different screen sizes and contexts
Basic Radio Group
<script>
import { RadioGroup } from "@kareyes/aether";
import type { RadioGroupOption } from "@kareyes/aether";
let selectedValue = $state("option1");
const options: RadioGroupOption[] = [
{ id: "1", label: "Option 1", value: "option1" },
{ id: "2", label: "Option 2", value: "option2" },
{ id: "3", label: "Option 3", value: "option3" },
];
</script>
<RadioGroup
{options}
bind:value={selectedValue}
label="Choose an option"
/>
Card Style for Prominent Selections
<script>
import { RadioGroup } from "@kareyes/aether";
let selectedPlan = $state("pro");
const planOptions = [
{
id: "free",
label: "Free Plan",
value: "free",
description: "Basic features for personal use - $0/month"
},
{
id: "pro",
label: "Pro Plan",
value: "pro",
description: "Advanced features for professionals - $29/month"
},
];
</script>
<RadioGroup
options={planOptions}
bind:value={selectedPlan}
isCard={true}
label="Choose Your Plan"
description="Select the plan that best fits your needs"
/>
Horizontal Layout for Compact Choices
<script>
import { RadioGroup } from "@kareyes/aether";
let theme = $state("auto");
const themeOptions = [
{ id: "light", label: "Light", value: "light" },
{ id: "dark", label: "Dark", value: "dark" },
{ id: "auto", label: "Auto", value: "auto" },
];
</script>
<RadioGroup
options={themeOptions}
bind:value={theme}
orientation="horizontal"
label="Theme Selection"
/>
Different Sizes
<script>
const options = [
{ id: "1", label: "Option 1", value: "option1" },
{ id: "2", label: "Option 2", value: "option2" },
];
</script>
<!-- Small -->
<RadioGroup
{options}
radioSize="sm"
label="Small Radio Group"
/>
<!-- Large -->
<RadioGroup
{options}
radioSize="lg"
label="Large Radio Group"
/>
Components
RadioGroup
The main component that manages radio group state using an options array pattern.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
options |
RadioGroupOption[] |
[] |
Array of radio options |
value |
string |
"" |
Currently selected value (bindable) |
orientation |
"vertical" | "horizontal" |
"vertical" |
Layout direction |
radioSize |
"sm" | "default" | "lg" |
"default" |
Size of individual radio buttons |
variant |
"default" | "destructive" | "success" | "warning" |
"default" |
Visual variant |
isCard |
boolean |
false |
Enable card-style layout with clickable cards |
disabled |
boolean |
false |
Disable the entire radio group |
error |
boolean |
false |
Error state with visual feedback |
label |
string |
undefined |
Group label |
description |
string |
undefined |
Group description |
required |
boolean |
false |
Whether field is required |
class |
string |
undefined |
Additional CSS classes |
onValueChange |
(value: string) => void |
undefined |
Callback when value changes |
onError |
(error: boolean) => void |
undefined |
Callback when error state changes |
Option Structure
interface RadioGroupOption {
id: string; // Unique identifier
label: string; // Display text
value: string; // Value to be selected
description?: string; // Optional description text
disabled?: boolean; // Whether this specific option is disabled
}
Layout Modes
Regular Mode (isCard={false}, default)
- Standard radio button layout
- Radio button with label/description
- Compact and familiar interface
- Best for most form applications
Card Mode (isCard={true})
- Card-style layout with clickable cards
- Radio button positioned on the right
- Enhanced visual hierarchy
- Perfect for options with descriptions
- Hover and selected states with border highlights
- Ideal for prominent selections (plans, cluster types, etc.)
Variants
Default (default)
- Standard styling with primary color
- Clean, minimal appearance
- Best for most use cases
Destructive (destructive)
- Red color scheme for dangerous actions
- Use for delete confirmations or warnings
Success (success)
- Green color scheme for positive actions
- Good for confirmations or approvals
Warning (warning)
- Yellow/orange color scheme for caution
- Use for actions requiring attention
Sizes
Small (sm)
- Compact radio buttons (12px / size-3)
- Reduced spacing (8px / gap-2)
- Smaller indicator icon (6px / size-1.5)
- Best for dense layouts or secondary options
Default (default)
- Standard radio buttons (16px / size-4)
- Normal spacing (12px / gap-3)
- Standard indicator icon (8px / size-2)
- Recommended for most use cases
Large (lg)
- Larger radio buttons (20px / size-5)
- Increased spacing (16px / gap-4)
- Bigger indicator icon (10px / size-2.5)
- Better for accessibility and touch interfaces
Advanced Features
Card Style Examples
Cluster Selection
<script>
let clusterType = $state("kubernetes");
const clusterOptions = [
{
id: "k8s",
label: "Kubernetes",
value: "kubernetes",
description: "Run GPU workloads on a K8s configured cluster."
},
{
id: "vm",
label: "Virtual Machine",
value: "vm",
description: "Access a VM configured cluster to run GPU workloads."
},
];
</script>
<RadioGroup
options={clusterOptions}
bind:value={clusterType}
isCard={true}
radioSize="lg"
label="Select Cluster Type"
description="Choose how you want to run your workloads"
/>
Card Style with Variants
<RadioGroup
options={planOptions}
bind:value={selectedPlan}
isCard={true}
variant="success"
label="Choose Your Plan"
/>
Error States
<script>
let selection = $state("");
let hasError = $derived(!selection);
</script>
<RadioGroup
{options}
bind:value={selection}
error={hasError}
required
label="Required Selection"
description="Please select an option"
/>
With Field Component
<script>
import { Field } from "@kareyes/aether";
let cluster = $state("");
</script>
<Field
label="Cluster Configuration"
description="Select your cluster type"
error={!cluster ? "Please select a cluster type" : undefined}
required
>
<RadioGroup
options={clusterOptions}
bind:value={cluster}
error={!cluster}
isCard={true}
/>
</Field>
Examples
Settings Panel
<script>
let notifications = $state("email");
</script>
<div class="space-y-4">
<h3 class="text-lg font-medium">Notification Preferences</h3>
<RadioGroup bind:value={notifications}>
<div class="flex items-center space-x-2">
<RadioGroupItem value="email" id="notify-email" />
<label for="notify-email" class="text-sm font-medium cursor-pointer">
📧 Email notifications
</label>
</div>
<div class="flex items-center space-x-2">
<RadioGroupItem value="push" id="notify-push" />
<label for="notify-push" class="text-sm font-medium cursor-pointer">
📱 Push notifications
</label>
</div>
<div class="flex items-center space-x-2">
<RadioGroupItem value="none" id="notify-none" />
<label for="notify-none" class="text-sm font-medium cursor-pointer">
🔕 No notifications
</label>
</div>
</RadioGroup>
</div>
Pricing Plans
<script>
let selectedPlan = $state("pro");
</script>
<div class="space-y-4">
<h3 class="text-lg font-medium">Choose Your Plan</h3>
<RadioGroup variant="card" bind:value={selectedPlan}>
<div class="flex items-center space-x-3 p-4">
<RadioGroupItem variant="card" value="free" id="plan-free" />
<div class="flex-1">
<label for="plan-free" class="text-sm font-medium cursor-pointer">
Free Plan
</label>
<p class="text-xs text-muted-foreground">$0/month</p>
<p class="text-xs text-muted-foreground">Basic features</p>
</div>
</div>
<div class="flex items-center space-x-3 p-4">
<RadioGroupItem variant="card" value="pro" id="plan-pro" />
<div class="flex-1">
<label for="plan-pro" class="text-sm font-medium cursor-pointer">
Pro Plan
</label>
<p class="text-xs text-muted-foreground">$10/month</p>
<p class="text-xs text-muted-foreground">Advanced features</p>
</div>
</div>
</RadioGroup>
</div>
Quick Toggle Options
<script>
let viewMode = $state("list");
</script>
<div class="space-y-2">
<label class="text-sm font-medium">View Mode</label>
<RadioGroup variant="inline" bind:value={viewMode}>
<div class="flex items-center space-x-2">
<RadioGroupItem variant="inline" value="list" id="view-list" />
<label for="view-list" class="text-sm cursor-pointer">📋 List</label>
</div>
<div class="flex items-center space-x-2">
<RadioGroupItem variant="inline" value="grid" id="view-grid" />
<label for="view-grid" class="text-sm cursor-pointer">⚏ Grid</label>
</div>
<div class="flex items-center space-x-2">
<RadioGroupItem variant="inline" value="table" id="view-table" />
<label for="view-table" class="text-sm cursor-pointer">📊 Table</label>
</div>
</RadioGroup>
</div>
Styling
The component uses Tailwind CSS and tailwind-variants for styling. Customization options:
CSS Variables
:root {
--color-primary: /* indicator fill color */
--color-border-input: /* border color */
--color-ring: /* focus ring color */
--color-card: /* card variant background */
--color-border: /* card variant border */
}
Custom Variants
// Extend the radioGroupVariants
export const customRadioGroupVariants = tv({
extend: radioGroupVariants,
variants: {
variant: {
...radioGroupVariants.variants.variant,
custom: "bg-gradient-to-r from-blue-50 to-purple-50 p-6 rounded-xl",
},
},
});
Accessibility
- Keyboard Navigation: Arrow keys navigate between options, Space selects
- Screen Readers: Proper ARIA roles and state announcements
- Focus Management: Clear visual focus indicators
- Labels: Proper label association with
forattributes - Group Context: Radio group role provides context to assistive technology
ARIA Attributes
role="radiogroup"- Applied to the RadioGroup containerrole="radio"- Applied to each RadioGroupItemaria-checked- Indicates the checked statearia-disabled- Indicates disabled state
Keyboard Support
| Key | Action |
|---|---|
Tab |
Move focus to/from the radio group |
Arrow Keys |
Navigate between radio options |
Space |
Select the focused radio option |
TypeScript
import type {
RadioGroupVariant,
RadioGroupSize,
RadioGroupItemVariant,
RadioGroupItemSize
} from "@kareyes/aether";
// Group variant and size types
type GroupVariant = RadioGroupVariant; // "default" | "card" | "inline"
type GroupSize = RadioGroupSize; // "sm" | "default" | "lg"
// Item variant and size types
type ItemVariant = RadioGroupItemVariant; // "default" | "card" | "inline"
type ItemSize = RadioGroupItemSize; // "sm" | "default" | "lg"
Best Practices
- Consistent Variants: Use the same variant for both RadioGroup and RadioGroupItem
- Proper Labels: Always provide clear, descriptive labels
- Logical Grouping: Group related options together
- Default Selection: Consider providing a sensible default value
- Validation: Implement proper form validation for required fields
- Accessibility: Test with keyboard navigation and screen readers
Form Integration
<script>
import { RadioGroup, RadioGroupItem } from "@kareyes/aether";
let formData = $state({
plan: "free",
billing: "monthly",
notifications: "email"
});
function handleSubmit() {
console.log("Form data:", formData);
}
</script>
<form on:submit|preventDefault={handleSubmit}>
<div class="space-y-6">
<div>
<label class="text-sm font-medium">Plan</label>
<RadioGroup variant="card" bind:value={formData.plan}>
<!-- options -->
</RadioGroup>
</div>
<div>
<label class="text-sm font-medium">Billing</label>
<RadioGroup variant="inline" bind:value={formData.billing}>
<!-- options -->
</RadioGroup>
</div>
<button type="submit">Submit</button>
</div>
</form>
Common Patterns
Multi-step Forms
Use card variant for plan selection and preference screens.
Settings Panels
Use default variant for configuration options.
Quick Filters
Use inline variant for view modes and sorting options.
Surveys
Use appropriate variant based on question complexity.
Using RadioGroup with Field Component
The Field component provides a consistent way to add labels, descriptions, and error handling to your RadioGroup components. RadioGroup already has built-in label and description props, but Field adds additional structure and validation capabilities.
Basic Field Usage
<script>
import { RadioGroup } from "@kareyes/aether";
import type { RadioGroupOption } from "@kareyes/aether";
import { Field } from "@kareyes/aether";
let selectedPlan = $state("pro");
const planOptions: RadioGroupOption[] = [
{ id: "free", label: "Free Plan", value: "free", description: "$0/month" },
{ id: "pro", label: "Pro Plan", value: "pro", description: "$29/month" },
{ id: "enterprise", label: "Enterprise", value: "enterprise", description: "$99/month" },
];
</script>
<Field
label="Subscription Plan"
description="Choose the plan that fits your needs"
required
>
<RadioGroup
options={planOptions}
bind:value={selectedPlan}
/>
</Field>
With Validation
<script>
import { RadioGroup } from "@kareyes/aether";
import { FieldPrimitives } from "@kareyes/aether";
let paymentMethod = $state("");
let error = $derived(paymentMethod === "");
const paymentOptions = [
{ id: "card", label: "Credit Card", value: "card" },
{ id: "paypal", label: "PayPal", value: "paypal" },
{ id: "bank", label: "Bank Transfer", value: "bank" },
];
</script>
<Field
label="Payment Method"
description="Select your preferred payment method"
required
error={error ? "Please select a payment method" : undefined}
>
<RadioGroup
options={paymentOptions}
bind:value={paymentMethod}
error={error}
/>
</Field>
Card Variant with Field
<script>
import { RadioGroup } from "@kareyes/aether";
import { FieldPrimitives } from "@kareyes/aether";
let selectedPlan = $state("pro");
const planOptions = [
{
id: "free",
label: "Free Plan",
value: "free",
description: "Basic features for personal use - $0/month"
},
{
id: "pro",
label: "Pro Plan",
value: "pro",
description: "Advanced features for professionals - $29/month"
},
{
id: "enterprise",
label: "Enterprise",
value: "enterprise",
description: "Custom solutions for large teams - $99/month"
},
];
</script>
<Field
label="Choose Your Plan"
description="Select the subscription tier that best fits your needs"
>
<RadioGroup
options={planOptions}
bind:value={selectedPlan}
isCard={true}
variant="success"
/>
</Field>
Horizontal Layout with Field
<Field
label="Notification Frequency"
description="How often would you like to receive updates?"
>
<RadioGroup
options={[
{ id: "realtime", label: "Real-time", value: "realtime" },
{ id: "daily", label: "Daily", value: "daily" },
{ id: "weekly", label: "Weekly", value: "weekly" },
]}
orientation="horizontal"
radioSize="lg"
/>
</Field>
Multiple RadioGroups in Form
<script>
import { RadioGroup } from "@kareyes/aether";
import { FieldPrimitives,Field } from "@kareyes/aether";
import { Button } from "@kareyes/aether";
let formData = $state({
plan: "pro",
billing: "monthly",
support: "email",
});
const planOptions = [
{ id: "free", label: "Free", value: "free", description: "$0/month" },
{ id: "pro", label: "Pro", value: "pro", description: "$29/month" },
{ id: "enterprise", label: "Enterprise", value: "enterprise", description: "$99/month" },
];
const billingOptions = [
{ id: "monthly", label: "Monthly", value: "monthly", description: "Pay monthly" },
{ id: "yearly", label: "Yearly", value: "yearly", description: "Save 20%" },
];
const supportOptions = [
{ id: "email", label: "Email Support", value: "email" },
{ id: "chat", label: "Live Chat", value: "chat" },
{ id: "phone", label: "Phone Support", value: "phone" },
];
function handleSubmit() {
console.log("Form data:", formData);
}
</script>
<FieldPrimitives.Set>
<FieldPrimitives.Legend>Subscription Settings</FieldPrimitives.Legend>
<FieldPrimitives.Description>Configure your subscription preferences</FieldPrimitives.Description>
<FieldPrimitives.Separator />
<FieldPrimitives.Group class="gap-6">
<Field
label="Plan Selection"
description="Choose your subscription tier"
required
>
<RadioGroup
options={planOptions}
bind:value={formData.plan}
isCard={true}
/>
</Field>
<Field
label="Billing Cycle"
description="Select how you'd like to be billed"
required
>
<RadioGroup
options={billingOptions}
bind:value={formData.billing}
orientation="horizontal"
radioSize="lg"
/>
</Field>
<Field
label="Support Channel"
description="Preferred method for customer support"
>
<RadioGroup
options={supportOptions}
bind:value={formData.support}
variant="success"
/>
</Field>
</FieldPrimitives.Group>
<div class="flex gap-4 pt-4">
<Button onclick={handleSubmit}>Save Preferences</Button>
<Button variant="outline" type="button">Cancel</Button>
</div>
</FieldPrimitives.Set>