RadioGroup
A single-choice selection component built on MUI RadioGroup. Supports standalone usage, seamless DashForm integration with automatic field binding, validation error gating, and reactive visibility. Perfect for account type selection, shipping methods, plan tiers, and mutually exclusive choices.
Quick Start
Copy & Paste
import { RadioGroup } from '@dashforge/ui';
<RadioGroup
name="accountType"
label="Account Type"
options={[
{ value: 'personal', label: 'Personal' },
{ value: 'business', label: 'Business' }
]}
/>Examples
Common RadioGroup patterns and configurations
Basic
Single choice from mutually exclusive options
<RadioGroup
name="accountType"
label="Account Type"
options={[
{ value: 'personal', label: 'Personal' },
{ value: 'business', label: 'Business' }
]}
/>With Default Value
Pre-select an option at render time
<RadioGroup
name="shipping"
label="Shipping Method"
defaultValue="standard"
options={[
{ value: 'standard', label: 'Standard (5-7 days)' },
{ value: 'express', label: 'Express (2-3 days)' },
{ value: 'overnight', label: 'Overnight' }
]}
/>Horizontal Layout
Display options side-by-side with row prop
<RadioGroup
name="plan"
label="Plan"
row
options={[
{ value: 'free', label: 'Free' },
{ value: 'pro', label: 'Pro' },
{ value: 'enterprise', label: 'Enterprise' }
]}
/>With Disabled Option
Restrict specific choices from selection
<RadioGroup
name="contact"
label="Contact Method"
options={[
{ value: 'email', label: 'Email' },
{ value: 'phone', label: 'Phone' },
{ value: 'sms', label: 'SMS', disabled: true }
]}
/>Error State
Validation feedback for required selections
Please select an account type
<RadioGroup
name="accountError"
label="Account Type"
options={[
{ value: 'personal', label: 'Personal' },
{ value: 'business', label: 'Business' }
]}
error
helperText="Please select an account type"
/>Without Label
Render options without a group label
<RadioGroup
name="standalone"
options={[
{ value: 'option1', label: 'Option 1' },
{ value: 'option2', label: 'Option 2' }
]}
/>Capabilities
Progressive adoption model from simple controlled component to reactive form integration
RadioGroup is designed for progressive adoption. Use it as a simple controlled component, integrate it with React Hook Form, or leverage Dashforge-native reactive capabilities. Choose the level that fits your team's workflow.
Controlled
Available Now
RadioGroup works as a standard React controlled component with familiar patterns. No proprietary lock-in required.
Standard value and onChange props
No proprietary lock-in
Easy incremental adoption
<RadioGroup
value={accountType}
onChange={(e) => setAccountType(e.target.value)}
name="accountType"
options={[
{ value: 'personal', label: 'Personal' },
{ value: 'business', label: 'Business' }
]}
/>React Hook Form Ready
Integration-Friendly
Designed to integrate with React Hook Form workflows through DashForm. Compatible with existing form-library patterns.
Works through DashForm bridge
Validation and error handling supported
Fits existing RHF workflows
<DashForm>
<RadioGroup
name="shippingMethod"
label="Shipping Method"
options={shippingOptions}
rules={{ required: 'Please select a method' }}
/>
</DashForm>Reactive Visibility
Available Now
RadioGroup can participate in engine-driven visibility rules through visibleWhen. Use it when single-choice depends on other form state.
Conditional rendering via visibleWhen
Engine evaluates the predicate
Useful for dependent choice fields
<RadioGroup
name="businessType"
label="Business Type"
options={businessTypes}
visibleWhen={(engine) =>
engine.getNode('accountType')?.value === 'business'
}
/>Access Control (RBAC)
RadioGroup supports RBAC at two levels: group-level access controls the entire field, while option-level access controls individual choices. Group-level access has precedence.
Hide when unauthorized
<RadioGroup
name="role"
label="Role"
access={{
resource: 'user.role',
action: 'read',
onUnauthorized: 'hide'
}}
options={[
{ value: 'viewer', label: 'Viewer' },
{ value: 'editor', label: 'Editor' }
]}
/>Disable when cannot edit
<RadioGroup
name="role"
label="Role"
access={{
resource: 'user.role',
action: 'update',
onUnauthorized: 'readonly'
}}
options={[
{ value: 'viewer', label: 'Viewer' },
{ value: 'editor', label: 'Editor' }
]}
/>
// Note: RadioGroup becomes disabled when readonlyRestrict specific options
<RadioGroup
name="role"
label="Role"
options={[
{ value: 'viewer', label: 'Viewer' },
{ value: 'editor', label: 'Editor' },
{
value: 'admin',
label: 'Admin',
access: {
resource: 'user.role.admin',
action: 'assign',
onUnauthorized: 'disable'
}
}
]}
/>Combined with visibleWhen
<RadioGroup
name="businessType"
label="Business Type"
visibleWhen={(e) =>
e.getValue('accountType') === 'business'
}
access={{
resource: 'account.businessType',
action: 'edit',
onUnauthorized: 'readonly'
}}
options={[
{ value: 'llc', label: 'LLC' },
{ value: 'corp', label: 'Corporation' }
]}
/>Note: When combining visibleWhen with RBAC, both conditions must be satisfied. RadioGroup becomes disabled when readonly (no native readonly support). If a hidden option is selected, it remains visible but disabled.
Form Integration
Real-world scenarios showing RadioGroup integrated with DashForm for validation, error handling, and reactive behavior.
RadioGroup works in real form contexts, not just isolated demos. Try these live scenarios to experience DashForm integration and reactive visibility—both fully implemented and production-ready.
Scenario 1
React Hook Form Integration
Try it: Select options and submit the form
RadioGroup integrates seamlessly with React Hook Form through DashForm. Components self-register, errors display automatically after interaction, and validation follows familiar RHF patterns. Try submitting without selecting options to see validation in action.
import { DashForm } from '@dashforge/forms';
import { RadioGroup } from '@dashforge/ui';
function CheckoutForm() {
const handleSubmit = (data: FormData) => {
console.log('Submitted:', data);
};
return (
<DashForm
defaultValues={{
shippingMethod: '',
contactPreference: ''
}}
onSubmit={handleSubmit}
mode="onBlur"
>
<RadioGroup
name="shippingMethod"
label="Shipping Method"
options={[
{ value: 'standard', label: 'Standard (5-7 days) - Free' },
{ value: 'express', label: 'Express (2-3 days) - $9.99' },
{ value: 'overnight', label: 'Overnight - $24.99' }
]}
rules={{
required: 'Please select a shipping method'
}}
/>
<RadioGroup
name="contactPreference"
label="Contact Preference"
options={[
{ value: 'email', label: 'Email' },
{ value: 'phone', label: 'Phone' }
]}
rules={{
required: 'Please select a contact method'
}}
/>
<button type="submit">Complete Order</button>
</DashForm>
);
}
// RadioGroup automatically:
// - Registers with React Hook Form
// - Syncs selected value from form state
// - Displays validation errors when touched
// - Tracks touched state on blurWhy This Matters
Gradual adoption: Drop RadioGroup into existing form architectures without rewriting validation logic or state management. Perfect for checkout flows and preference selection.
Scenario 2
Reactive Conditional Visibility
Try it: Select "Business" to see conditional radio group appear
RadioGroup supports conditional rendering through the visibleWhen prop. Fields render based on engine state—components query field values and make rendering decisions. Select "Business" account type to see the business type radio group appear instantly without manual state orchestration. This is part of Dashforge Reactive V2 architecture.
import { DashForm } from '@dashforge/forms';
import { RadioGroup, Select } from '@dashforge/ui';
function AccountSetupForm() {
return (
<DashForm
defaultValues={{
accountType: '',
businessType: '',
contactMethod: ''
}}
>
<Select
name="accountType"
label="Account Type"
options={[
{ value: 'personal', label: 'Personal' },
{ value: 'business', label: 'Business' }
]}
/>
<RadioGroup
name="contactMethod"
label="Preferred Contact Method"
options={[
{ value: 'email', label: 'Email' },
{ value: 'phone', label: 'Phone' },
{ value: 'mail', label: 'Mail' }
]}
/>
{/* Business type: renders only for business accounts */}
<RadioGroup
name="businessType"
label="Business Type"
options={[
{ value: 'sole-proprietor', label: 'Sole Proprietor' },
{ value: 'llc', label: 'LLC' },
{ value: 'corporation', label: 'Corporation' }
]}
visibleWhen={(engine) => {
const accountType = engine.getNode('accountType')?.value;
return accountType === 'business';
}}
rules={{
required: 'Please select a business type'
}}
/>
</DashForm>
);
}
// The Engine API provides:
// - getNode(name): Access any field's state
// - Component re-renders on dependency changes
// - Component makes rendering decision (engine provides state)Why This Matters
Build adaptive forms where radio group visibility responds to user input. The component handles conditional rendering—you define the predicate. Perfect for multi-step flows that branch based on user choices.
API Reference
Complete RadioGroup props and type definitions
Explicit vs Auto-Bound Props: When inside DashForm, RadioGroup receives value, error, helperText, onChange, and onBlur automatically through field binding. Explicit props always take precedence over form-provided values.
| Prop | Type | Default | Description |
|---|---|---|---|
| name | string | - | Field name for form integration (required) |
| options | RadioGroupOption[] | - | Array of radio options. Each option has: { value: string, label: React.ReactNode, disabled?: boolean }. Required prop that defines available choices. |
| label | React.ReactNode | - | Label text displayed above the radio group. When provided, wraps the group in FormLabel. |
| value | string | - | Controlled selected value of the radio group |
| onChange | (event, value) => void | - | Callback fired when the selected value changes. Receives both the event and the new value. |
| row | boolean | false | If true, displays radio buttons horizontally. Default is vertical layout. |
| error | boolean | false | If true, displays error state. Explicit error prop overrides form-provided error state. When inside DashForm without explicit prop, error is gated (shows only when touched OR submitted). |
| helperText | string | - | Helper text displayed below radio group. Explicit helperText prop overrides form-provided validation error message. When inside DashForm, validation errors display as helperText (gated by touched/submitted state). |
| rules | ValidationRules | - | Validation rules for DashForm integration. Format follows React Hook Form rules contract. Only used when inside DashForm—ignored in standalone mode. Common rule: { required: "message" } for mandatory selection. |
| visibleWhen | (engine: Engine) => boolean | - | Component-level conditional rendering predicate. Receives engine instance with access to all field state via getNode(name). When false, component renders null. Re-evaluates on dependency changes. Only works inside DashForm (requires engine). |
Under the hood
How RadioGroup works internally
Form integration
Automatically binds to form state inside DashForm. No Controller, no manual wiring. Works as a standard MUI RadioGroup when used standalone.
Behavior model
Options array prop for cleaner, declarative code. Errors appear only after blur or submit. Enforces single-choice selection semantics—only one option can be selected at a time.
Architecture
Built on MUI RadioGroup with FormControlLabel wrappers. Fully typed with TypeScript. Purpose-built for account types, shipping methods, plan tiers, and any mutually exclusive choice.