Skip to content

Radio

Radio provides a comprehensive solution for single-choice selection with built-in animations, group management, and multiple styling variants. It supports both controlled and uncontrolled usage with smooth spring animations and visual feedback.

import {
RadioGroup,
Radio,
RadioIndicator,
RadioIcon,
RadioLabel
} from 'rnc-theme';
const [selected, setSelected] = useState('option1');
<RadioGroup value={selected} onValueChange={setSelected}>
<Radio value="option1">
<RadioLabel>Option 1</RadioLabel>
</Radio>
<Radio value="option2">
<RadioLabel>Option 2</RadioLabel>
</Radio>
<Radio value="option3">
<RadioLabel>Option 3</RadioLabel>
</Radio>
</RadioGroup>
PropTypeDefaultDescription
childrenReact.ReactNode-Radio components to render
valuestring''Currently selected radio value
onValueChange(value: string) => void-Callback when selection changes
disabledbooleanfalseDisable entire radio group
styleStyleProp<ViewStyle>-Additional container styles
PropTypeDefaultDescription
valuestring-Required. Unique identifier for radio
checkedboolean-Controlled checked state (individual use)
onCheckedChange(checked: boolean) => void-Callback for individual radio changes
sizeComponentSize'md'Radio size (xs, sm, md, lg, xl)
variantComponentVariant'default'Visual style variant
disabledbooleanfalseDisable this specific radio
childrenReact.ReactNode-RadioLabel and other content
styleStyleProp<ViewStyle>-Additional radio styles
PropTypeDefaultDescription
childrenReact.ReactNode-Custom indicator content
sizeComponentSize'md'Indicator size
variantComponentVariant'default'Indicator variant
styleStyleProp<ViewStyle>-Additional indicator styles
PropTypeDefaultDescription
iconReact.ReactNode-Custom icon component
sizeComponentSize'md'Icon size
variantComponentVariant'default'Icon variant
styleStyleProp<ViewStyle>-Additional icon styles
PropTypeDefaultDescription
childrenReact.ReactNode-Required. Label text content
sizeComponentSize'md'Label text size
styleTextStyle-Additional label styles
VariantDescriptionUse Case
defaultStandard radio appearanceGeneral form inputs
primaryPrimary brand colorImportant selections
secondarySecondary brand colorAlternative selections
outlineOutlined styleMinimal designs
filledFilled backgroundProminent selections
ghostSubtle appearanceLow-emphasis choices
successSuccess state colorConfirmation choices
errorError state colorInvalid selections
warningWarning state colorCaution choices
infoInformation colorInfo selections
destructiveDestructive action colorDeletion confirmations
const SettingsForm = () => {
const [theme, setTheme] = useState('light');
const [notifications, setNotifications] = useState('all');
const [language, setLanguage] = useState('en');
return (
<VStack spacing="xl" padding="lg">
{/* Theme Selection */}
<VStack spacing="md">
<Text style={{ fontSize: 16, fontWeight: '600' }}>Theme</Text>
<RadioGroup value={theme} onValueChange={setTheme}>
<Radio value="light" variant="primary">
<RadioLabel>Light Mode</RadioLabel>
</Radio>
<Radio value="dark" variant="primary">
<RadioLabel>Dark Mode</RadioLabel>
</Radio>
<Radio value="auto" variant="primary">
<RadioLabel>System Default</RadioLabel>
</Radio>
</RadioGroup>
</VStack>
{/* Notification Settings */}
<VStack spacing="md">
<Text style={{ fontSize: 16, fontWeight: '600' }}>Notifications</Text>
<RadioGroup value={notifications} onValueChange={setNotifications}>
<Radio value="all" variant="success">
<RadioLabel>All Notifications</RadioLabel>
</Radio>
<Radio value="important" variant="warning">
<RadioLabel>Important Only</RadioLabel>
</Radio>
<Radio value="none" variant="error">
<RadioLabel>None</RadioLabel>
</Radio>
</RadioGroup>
</VStack>
{/* Language Selection */}
<VStack spacing="md">
<Text style={{ fontSize: 16, fontWeight: '600' }}>Language</Text>
<RadioGroup value={language} onValueChange={setLanguage}>
<Radio value="en" size="sm">
<RadioLabel>English</RadioLabel>
</Radio>
<Radio value="id" size="sm">
<RadioLabel>Bahasa Indonesia</RadioLabel>
</Radio>
<Radio value="es" size="sm">
<RadioLabel>Español</RadioLabel>
</Radio>
</RadioGroup>
</VStack>
</VStack>
);
};
<VStack spacing="lg" padding="lg">
<Text style={{ fontSize: 18, fontWeight: 'bold' }}>Radio Sizes</Text>
<VStack spacing="md">
<Radio value="xs" size="xs" checked>
<RadioLabel size="xs">Extra Small Radio</RadioLabel>
</Radio>
<Radio value="sm" size="sm" checked>
<RadioLabel size="sm">Small Radio</RadioLabel>
</Radio>
<Radio value="md" size="md" checked>
<RadioLabel size="md">Medium Radio (Default)</RadioLabel>
</Radio>
<Radio value="lg" size="lg" checked>
<RadioLabel size="lg">Large Radio</RadioLabel>
</Radio>
<Radio value="xl" size="xl" checked>
<RadioLabel size="xl">Extra Large Radio</RadioLabel>
</Radio>
</VStack>
</VStack>
const SubscriptionPlans = () => {
const [selectedPlan, setSelectedPlan] = useState('basic');
const plans = [
{
id: 'basic',
name: 'Basic Plan',
price: '$9.99/month',
features: ['10 Projects', '5GB Storage', 'Email Support'],
variant: 'outline'
},
{
id: 'pro',
name: 'Pro Plan',
price: '$19.99/month',
features: ['Unlimited Projects', '100GB Storage', 'Priority Support'],
variant: 'primary'
},
{
id: 'enterprise',
name: 'Enterprise Plan',
price: '$49.99/month',
features: ['Everything in Pro', 'Custom Integrations', '24/7 Phone Support'],
variant: 'success'
}
];
return (
<VStack spacing="lg" padding="lg">
<Text style={{ fontSize: 20, fontWeight: 'bold', textAlign: 'center' }}>
Choose Your Plan
</Text>
<RadioGroup value={selectedPlan} onValueChange={setSelectedPlan}>
{plans.map(plan => (
<Box
key={plan.id}
variant="card"
padding="lg"
style={{
borderWidth: selectedPlan === plan.id ? 2 : 1,
borderColor: selectedPlan === plan.id ? '#007AFF' : '#E0E0E0'
}}
>
<Radio value={plan.id} variant={plan.variant}>
<VStack spacing="sm" flex={1}>
<HStack justify="space-between" align="center">
<RadioLabel style={{ fontSize: 18, fontWeight: '600' }}>
{plan.name}
</RadioLabel>
<Text style={{ fontSize: 16, fontWeight: 'bold', color: '#007AFF' }}>
{plan.price}
</Text>
</HStack>
<VStack spacing="xs">
{plan.features.map((feature, index) => (
<Text key={index} style={{ fontSize: 14, color: '#666' }}>
{feature}
</Text>
))}
</VStack>
</VStack>
</Radio>
</Box>
))}
</RadioGroup>
<Button
title={`Subscribe to ${plans.find(p => p.id === selectedPlan)?.name}`}
variant="primary"
disabled={!selectedPlan}
/>
</VStack>
);
};
const PaymentMethods = () => {
const [paymentMethod, setPaymentMethod] = useState('');
return (
<VStack spacing="lg" padding="lg">
<Text style={{ fontSize: 18, fontWeight: '600' }}>Payment Method</Text>
<RadioGroup value={paymentMethod} onValueChange={setPaymentMethod}>
<Radio value="card" variant="primary">
<RadioIndicator>
<RadioIcon icon={<CreditCardIcon />} />
</RadioIndicator>
<VStack spacing="xs" flex={1}>
<RadioLabel style={{ fontWeight: '600' }}>Credit Card</RadioLabel>
<Text style={{ fontSize: 12, color: '#666' }}>
Pay with Visa, Mastercard, or American Express
</Text>
</VStack>
</Radio>
<Radio value="paypal" variant="secondary">
<RadioIndicator>
<RadioIcon icon={<PaypalIcon />} />
</RadioIndicator>
<VStack spacing="xs" flex={1}>
<RadioLabel style={{ fontWeight: '600' }}>PayPal</RadioLabel>
<Text style={{ fontSize: 12, color: '#666' }}>
Pay securely with your PayPal account
</Text>
</VStack>
</Radio>
<Radio value="apple" variant="ghost">
<RadioIndicator>
<RadioIcon icon={<AppleIcon />} />
</RadioIndicator>
<VStack spacing="xs" flex={1}>
<RadioLabel style={{ fontWeight: '600' }}>Apple Pay</RadioLabel>
<Text style={{ fontSize: 12, color: '#666' }}>
Pay with Touch ID or Face ID
</Text>
</VStack>
</Radio>
<Radio value="google" variant="ghost">
<RadioIndicator>
<RadioIcon icon={<GoogleIcon />} />
</RadioIndicator>
<VStack spacing="xs" flex={1}>
<RadioLabel style={{ fontWeight: '600' }}>Google Pay</RadioLabel>
<Text style={{ fontSize: 12, color: '#666' }}>
Pay with your Google account
</Text>
</VStack>
</Radio>
</RadioGroup>
</VStack>
);
};
const SurveyForm = () => {
const [satisfaction, setSatisfaction] = useState('');
const [frequency, setFrequency] = useState('');
const [recommendation, setRecommendation] = useState('');
return (
<VStack spacing="xl" padding="lg">
<Text style={{ fontSize: 20, fontWeight: 'bold' }}>Customer Survey</Text>
{/* Satisfaction Rating */}
<VStack spacing="md">
<Text style={{ fontSize: 16, fontWeight: '600' }}>
How satisfied are you with our service?
</Text>
<RadioGroup value={satisfaction} onValueChange={setSatisfaction}>
<Radio value="very-satisfied" variant="success" size="lg">
<RadioLabel>😍 Very Satisfied</RadioLabel>
</Radio>
<Radio value="satisfied" variant="primary" size="lg">
<RadioLabel>😊 Satisfied</RadioLabel>
</Radio>
<Radio value="neutral" variant="outline" size="lg">
<RadioLabel>😐 Neutral</RadioLabel>
</Radio>
<Radio value="dissatisfied" variant="warning" size="lg">
<RadioLabel>😞 Dissatisfied</RadioLabel>
</Radio>
<Radio value="very-dissatisfied" variant="error" size="lg">
<RadioLabel>😡 Very Dissatisfied</RadioLabel>
</Radio>
</RadioGroup>
</VStack>
{/* Usage Frequency */}
<VStack spacing="md">
<Text style={{ fontSize: 16, fontWeight: '600' }}>
How often do you use our product?
</Text>
<RadioGroup value={frequency} onValueChange={setFrequency}>
<Radio value="daily">
<RadioLabel>Daily</RadioLabel>
</Radio>
<Radio value="weekly">
<RadioLabel>Weekly</RadioLabel>
</Radio>
<Radio value="monthly">
<RadioLabel>Monthly</RadioLabel>
</Radio>
<Radio value="rarely">
<RadioLabel>Rarely</RadioLabel>
</Radio>
</RadioGroup>
</VStack>
{/* Recommendation */}
<VStack spacing="md">
<Text style={{ fontSize: 16, fontWeight: '600' }}>
Would you recommend us to others?
</Text>
<RadioGroup value={recommendation} onValueChange={setRecommendation}>
<Radio value="definitely" variant="success">
<RadioLabel>Definitely</RadioLabel>
</Radio>
<Radio value="probably" variant="primary">
<RadioLabel>Probably</RadioLabel>
</Radio>
<Radio value="maybe" variant="outline">
<RadioLabel>Maybe</RadioLabel>
</Radio>
<Radio value="probably-not" variant="warning">
<RadioLabel>Probably Not</RadioLabel>
</Radio>
<Radio value="definitely-not" variant="error">
<RadioLabel>Definitely Not</RadioLabel>
</Radio>
</RadioGroup>
</VStack>
<Button
title="Submit Survey"
variant="primary"
disabled={!satisfaction || !frequency || !recommendation}
/>
</VStack>
);
};
const DynamicRadioForm = () => {
const [category, setCategory] = useState('');
const [subcategory, setSubcategory] = useState('');
const categories = {
electronics: ['Smartphones', 'Laptops', 'Tablets', 'Accessories'],
clothing: ['Men', 'Women', 'Kids', 'Shoes'],
books: ['Fiction', 'Non-Fiction', 'Educational', 'Comics']
};
const subcategories = categories[category] || [];
return (
<VStack spacing="lg" padding="lg">
<VStack spacing="md">
<Text style={{ fontSize: 16, fontWeight: '600' }}>Category</Text>
<RadioGroup value={category} onValueChange={(value) => {
setCategory(value);
setSubcategory(''); // Reset subcategory
}}>
<Radio value="electronics">
<RadioLabel>Electronics</RadioLabel>
</Radio>
<Radio value="clothing">
<RadioLabel>Clothing</RadioLabel>
</Radio>
<Radio value="books">
<RadioLabel>Books</RadioLabel>
</Radio>
</RadioGroup>
</VStack>
{category && (
<VStack spacing="md">
<Text style={{ fontSize: 16, fontWeight: '600' }}>Subcategory</Text>
<RadioGroup value={subcategory} onValueChange={setSubcategory}>
{subcategories.map(sub => (
<Radio key={sub} value={sub.toLowerCase()}>
<RadioLabel>{sub}</RadioLabel>
</Radio>
))}
</RadioGroup>
</VStack>
)}
</VStack>
);
};
const ConditionalForm = () => {
const [userType, setUserType] = useState('');
const [experience, setExperience] = useState('');
const [companySize, setCompanySize] = useState('');
return (
<VStack spacing="lg" padding="lg">
<VStack spacing="md">
<Text style={{ fontSize: 16, fontWeight: '600' }}>I am a...</Text>
<RadioGroup value={userType} onValueChange={setUserType}>
<Radio value="individual">
<RadioLabel>Individual Developer</RadioLabel>
</Radio>
<Radio value="business">
<RadioLabel>Business User</RadioLabel>
</Radio>
<Radio value="student">
<RadioLabel>Student</RadioLabel>
</Radio>
</RadioGroup>
</VStack>
{userType === 'individual' && (
<VStack spacing="md">
<Text style={{ fontSize: 16, fontWeight: '600' }}>Experience Level</Text>
<RadioGroup value={experience} onValueChange={setExperience}>
<Radio value="beginner" variant="info">
<RadioLabel>Beginner (0-1 years)</RadioLabel>
</Radio>
<Radio value="intermediate" variant="primary">
<RadioLabel>Intermediate (2-5 years)</RadioLabel>
</Radio>
<Radio value="expert" variant="success">
<RadioLabel>Expert (5+ years)</RadioLabel>
</Radio>
</RadioGroup>
</VStack>
)}
{userType === 'business' && (
<VStack spacing="md">
<Text style={{ fontSize: 16, fontWeight: '600' }}>Company Size</Text>
<RadioGroup value={companySize} onValueChange={setCompanySize}>
<Radio value="startup" variant="outline">
<RadioLabel>Startup (1-10 employees)</RadioLabel>
</Radio>
<Radio value="small" variant="primary">
<RadioLabel>Small Business (11-50 employees)</RadioLabel>
</Radio>
<Radio value="medium" variant="secondary">
<RadioLabel>Medium Business (51-200 employees)</RadioLabel>
</Radio>
<Radio value="enterprise" variant="success">
<RadioLabel>Enterprise (200+ employees)</RadioLabel>
</Radio>
</RadioGroup>
</VStack>
)}
</VStack>
);
};
const ValidatedRadioForm = () => {
const [priority, setPriority] = useState('');
const [urgency, setUrgency] = useState('');
const [submitted, setSubmitted] = useState(false);
const handleSubmit = () => {
setSubmitted(true);
if (priority && urgency) {
// Process form
console.log('Form submitted:', { priority, urgency });
}
};
const priorityError = submitted && !priority;
const urgencyError = submitted && !urgency;
return (
<VStack spacing="lg" padding="lg">
<Text style={{ fontSize: 18, fontWeight: 'bold' }}>Support Ticket</Text>
<VStack spacing="md">
<Text style={{ fontSize: 16, fontWeight: '600' }}>
Priority Level *
</Text>
<RadioGroup value={priority} onValueChange={setPriority}>
<Radio value="low" variant={priorityError ? 'error' : 'success'}>
<RadioLabel>Low Priority</RadioLabel>
</Radio>
<Radio value="medium" variant={priorityError ? 'error' : 'warning'}>
<RadioLabel>Medium Priority</RadioLabel>
</Radio>
<Radio value="high" variant={priorityError ? 'error' : 'error'}>
<RadioLabel>High Priority</RadioLabel>
</Radio>
</RadioGroup>
{priorityError && (
<Text style={{ color: 'red', fontSize: 12 }}>
Please select a priority level
</Text>
)}
</VStack>
<VStack spacing="md">
<Text style={{ fontSize: 16, fontWeight: '600' }}>
Urgency *
</Text>
<RadioGroup value={urgency} onValueChange={setUrgency}>
<Radio value="can-wait" variant={urgencyError ? 'error' : 'outline'}>
<RadioLabel>Can Wait</RadioLabel>
</Radio>
<Radio value="soon" variant={urgencyError ? 'error' : 'primary'}>
<RadioLabel>Needed Soon</RadioLabel>
</Radio>
<Radio value="immediate" variant={urgencyError ? 'error' : 'destructive'}>
<RadioLabel>Immediate Attention</RadioLabel>
</Radio>
</RadioGroup>
{urgencyError && (
<Text style={{ color: 'red', fontSize: 12 }}>
Please select urgency level
</Text>
)}
</VStack>
<Button
title="Submit Ticket"
onPress={handleSubmit}
variant="primary"
/>
</VStack>
);
};

The Radio component uses smooth spring animations that can be customized through the theme configuration:

// Default animation configuration
const DEFAULT_SPRING_CONFIG = {
damping: 15,
stiffness: 200,
mass: 0.5
};
const BORDER_TIMING_CONFIG = {
duration: 200
};

UX Guidelines

  • Always provide clear, descriptive labels for radio options
  • Use RadioGroup for mutually exclusive choices
  • Limit radio groups to 2-7 options for optimal usability
  • Consider using dropdowns for more than 7 options

Visual Design

  • Use consistent variants within related forms
  • Provide adequate spacing between radio options
  • Use appropriate sizes based on touch target requirements
  • Consider using icons for visual distinction between options

Performance

  • Use React.memo for radio options in large lists
  • Avoid creating new callback functions in render
  • Consider using FlatList for very large radio option lists
  • Implement proper key props for dynamic radio options