Radio Component Design
Overview
The Radio component is a form component in this component library used for single selection. It continues the consistent design philosophy of our component library, adopting the principles of "separation of concerns" and "logic abstraction." It achieves powerful and flexible radio control functionality through core Hooks such as useInputState and useInputClasses.
The Radio component focuses on handling users' single selection operations, providing a complete and easy-to-use selection solution that supports individual radio buttons, radio groups, and button-style radio buttons in various forms.
Design Philosophy
Layered Architecture
The Radio component strictly follows a three-layer architecture design:
- Structure Layer radio.vue, radio-group.vue, radio-button.vue - Responsible for the component's DOM structure and basic layout
- Logic Layer radioComputed.ts - Handles complex reactive computations through Hooks
- Presentation Layer radio.scss, radio-group.scss, radio-button.scss - Defines the component's visual presentation and style rules
Logic Abstraction
The Radio component abstracts complex logic into multiple core Hooks:
- useInputState - Handles input state computation
- useInputClasses - Handles class name generation
This design allows the component itself to only declare the required logic, while the specific computations are handled by the Hooks.
Core Feature Design
Component Architecture
The Radio component adopts a modular design and includes the following three core components:
- MYRadio - Base radio component
- MYRadioGroup - Radio group container component
- MYRadioButton - Button-style radio component
Structured Props Design
The props of the Radio component are divided into multiple logical groups by function:
// Base radio properties
export const radioProps = {
modelValue: {
type: [String, Number] as PropType<string | number>,
default: ''
},
value: {
type: [String, Number] as PropType<string | number>,
default: ''
},
name: {
type: String as PropType<string>,
default: ''
},
size: {
type: String as PropType<string>,
default: ''
},
disabled: {
type: Boolean as PropType<boolean>,
default: false
}
} as const;// Radio group properties
export const radioGroupProps = {
modelValue: {
type: [String, Number, Boolean] as PropType<string | number | boolean>,
default: '',
},
disabled: {
type: Boolean,
default: false,
},
direction: {
type: String as PropType<'horizontal' | 'vertical'>,
default: 'horizontal',
},
gap: {
type: String,
default: '12px',
},
} as constDependency Injection Mechanism
The Radio component implements parent-child component communication through Vue's dependency injection mechanism:
// Provide context
provide('radioGroup', {
modelValue: computed(() => props.modelValue),
disabled: computed(() => props.disabled),
change: updateValue
})
// Inject context
const radioGroup = inject<RadioGroupContext | null>('radioGroup', null)This design enables seamless collaboration between the radio component and its parent group component.
Style System Design
Base Radio Styles
The base radio adopts a classic design:
.my-radio {
display: inline-flex;
align-items: center;
cursor: pointer;
&__inner {
width: 14px;
height: 14px;
border: 1px solid #dcdfe6;
border-radius: 50%;
background: #fff;
position: relative;
&:after {
content: "";
position: absolute;
width: 6px;
height: 6px;
border-radius: 50%;
background: #fff;
left: 50%;
top: 50%;
transform: translate(-50%, -50%) scale(0);
transition: transform 0.15s ease-in;
}
}
&--checked {
.my-radio__inner {
border-color: #409eff;
background-color: #409eff;
&:after {
transform: translate(-50%, -50%) scale(1);
}
}
}
}Button-style Radio
Button-style radio provides a modern appearance:
.my-radio-button {
position: relative;
display: inline-block;
box-sizing: border-box;
height: 36px;
line-height: 36px;
font-size: 14px;
font-weight: 500;
border: 1px solid #dcdfe6;
background: #fff;
color: #606266;
cursor: pointer;
transition: all 0.2s;
margin: 0;
padding: 0 16px;
border-radius: 0;
outline: none;
}Layout Control
Layout direction is controlled through the radio group:
- Horizontal Layout - Default layout method
- Vertical Layout - Implemented via
direction="vertical"
Component Structure Design
Overall Structure
The overall structure of the Radio component is as follows:
<!-- Base radio -->
<label class="my-radio">
<span class="my-radio__input">
<input class="my-radio__original" type="radio" />
<span class="my-radio__inner"></span>
</span>
<span class="my-radio__label">
<slot></slot>
</span>
</label>
<!-- Radio group -->
<div class="my-radio-group">
<slot></slot>
</div>Button-style Structure
Button-style radio has a special structure:
<label class="my-radio-button">
<input class="my-radio-button__original" type="radio" />
<span class="my-radio-button__inner">
<slot></slot>
</span>
</label>Interaction Design
Checked State Toggling
The Radio component supports clicking to toggle the checked state:
function handleClick() {
if (isDisabled.value) return
if (isGroup.value) {
radioGroup!.change?.(props.value)
} else {
emit('update:modelValue', props.value)
emit('change', props.value)
}
}Disabled State
The Radio component supports disabled state:
- Component-level disabling - Controlled via the disabled property
- Group-level disabling - Controlled via the disabled property of MYRadioGroup
Keyboard Navigation
The Radio component supports keyboard navigation:
- Tab Key - Switch focus between components
- Space Key - Select the currently focused radio button
Extensibility Design
The Radio component has excellent extensibility:
- Multiple Presentation Forms: Supports base radio and button-style radio
- Flexible Layout Control: Supports horizontal and vertical layouts
- Size Control: Supports multiple size options
- State Control: Supports disabled state
- Theme Adaptation: Supports theme customization through CSS variables
- Combined Usage: Seamlessly integrates with form components
Style Details
The Radio component has the following characteristics in style handling:
- Standardized Design: Adopts industry-standard radio styles
- Animation Effects: Smooth animation when toggling checked state
- Responsive Design: Supports flexible layout control
- Accessibility Design: Supports keyboard navigation and screen readers
- Consistency: Maintains style consistency with other form components in the component library
Performance Optimization
Performance is optimized through the following methods:
- Use computed properties to cache calculation results
- Move complex logic to independent hooks
- Avoid unnecessary re-renders
- Use Vue 3 Composition API to improve runtime efficiency
- Reasonably use dependency injection to reduce inter-component passing
Design Value
The Radio component continues the design philosophy of our component library:
- Separation of concerns: Structure, styles, and logic are completely decoupled
- High reusability: Abstract common logic through hooks
- Easy maintenance: Clear code structure and naming conventions
- Strong extensibility: Supports rich customization options
- Consistency: Maintains a consistent design language with other components such as Input and Form