Checkbox & Radio
Clean, Apple-inspired checkbox and radio button components with smooth animations, group management, selection limits, and comprehensive dark mode support.
Basic Usage
Use apple-checkbox for multiple selections and apple-radio
for single selections within a group. Each input is hidden and replaced with a
custom-styled control.
Standalone Checkbox
<div class="apple-input-group">
<label class="apple-input-wrapper apple-checkbox">
<input type="checkbox" name="standalone" value="agree">
<span class="apple-control"></span>
<span class="apple-label">I agree to the terms and conditions</span>
</label>
</div>
Standalone Radio Button
<div class="apple-input-group">
<label class="apple-input-wrapper apple-radio">
<input type="radio" name="gender" value="male">
<span class="apple-control"></span>
<span class="apple-label">Male</span>
</label>
<label class="apple-input-wrapper apple-radio">
<input type="radio" name="gender" value="female">
<span class="apple-control"></span>
<span class="apple-label">Female</span>
</label>
<label class="apple-input-wrapper apple-radio">
<input type="radio" name="gender" value="other">
<span class="apple-control"></span>
<span class="apple-label">Other</span>
</label>
</div>
Checkbox Group
<div class="apple-input-group">
<span class="apple-input-group-title">Select your interests</span>
<label class="apple-input-wrapper apple-checkbox">
<input type="checkbox" name="interests" value="design">
<span class="apple-control"></span>
<span class="apple-label">Design</span>
</label>
<!-- More checkboxes... -->
</div>
Radio Group
<div class="apple-input-group">
<span class="apple-input-group-title">Choose your plan</span>
<label class="apple-input-wrapper apple-radio">
<input type="radio" name="plan" value="free">
<span class="apple-control"></span>
<span class="apple-label">Free Plan</span>
</label>
<label class="apple-input-wrapper apple-radio">
<input type="radio" name="plan" value="pro" checked>
<span class="apple-control"></span>
<span class="apple-label">Pro Plan - $9/month</span>
</label>
</div>
Selection Limits
Use data-max on the group container to limit how many checkboxes
can be selected. When the limit is reached, remaining unchecked boxes become disabled.
<div class="apple-input-group" data-max="2">
<span class="apple-input-group-title">Choose up to 2 toppings</span>
<label class="apple-input-wrapper apple-checkbox">
<input type="checkbox" name="toppings" value="cheese">
<span class="apple-control"></span>
<span class="apple-label">Extra Cheese</span>
</label>
<!-- More checkboxes... -->
</div>
Disabled State
<!-- Disabled checkbox --> <label class="apple-input-wrapper apple-checkbox"> <input type="checkbox" disabled> <span class="apple-control"></span> <span class="apple-label">Disabled option</span> </label> <!-- Disabled radio --> <label class="apple-input-wrapper apple-radio"> <input type="radio" disabled> <span class="apple-control"></span> <span class="apple-label">Disabled option</span> </label>
Component Structure
Every checkbox/radio consists of these elements:
.apple-input-group— Container with optionaldata-max.apple-input-group-title— Optional group title.apple-input-wrapper— Label wrapper withapple-checkboxorapple-radio<input>— Hidden native input (checkbox or radio).apple-control— Custom styled control.apple-label— Text label
Animations
All interactions use smooth cubic-bezier transitions. The checkmark and radio dot appear with a satisfying animation when selected.
/* Smooth transitions for all states */
.apple-control {
transition: all 0.2s cubic-bezier(0.25, 0.8, 0.25, 1);
}
.apple-input-wrapper:hover input:not(:disabled) ~ .apple-control {
border-color: rgba(0, 0, 0, 0.4);
}
Dark Mode
Automatic dark mode support with appropriate color adjustments and Apple-inspired dark blue accent color.
Toggle to dark mode to see the dark theme styling.
Initialisation
// Checkboxes and radios are automatically initialized with initAll()
// No manual initialization needed!
import('@kerkhoff-ict/solora/dist/index.js')
.then(sol => sol.initAll());
Selection Limit Logic
The initAll() function automatically enforces selection limits by:
- Monitoring checkbox changes within groups that have
data-max - Counting currently selected checkboxes
- Disabling unchecked boxes when the limit is reached
- Re-enabling boxes when selections drop below the limit
// Example: Limit to 3 selections
const limitedGroups = document.querySelectorAll('.apple-input-group[data-max]');
limitedGroups.forEach(group => {
const maxAllowed = parseInt(group.getAttribute('data-max'), 10);
const checkboxes = group.querySelectorAll('input[type="checkbox"]');
checkboxes.forEach(checkbox => {
checkbox.addEventListener('change', () => {
const checkedCount = group.querySelectorAll('input[type="checkbox"]:checked').length;
if (checkedCount >= maxAllowed) {
checkboxes.forEach(cb => {
if (!cb.checked) cb.disabled = true;
});
} else {
checkboxes.forEach(cb => cb.disabled = false);
}
});
});
});
CSS Classes Reference
| Class | Type | Description |
|---|---|---|
.apple-input-group | Container | Wrapper for related inputs with optional data-max |
.apple-input-group-title | Title | Group heading text |
.apple-input-wrapper | Wrapper | Label wrapper that contains input, control, and label |
.apple-checkbox | Type | Styles wrapper for checkbox (square control) |
.apple-radio | Type | Styles wrapper for radio button (round control) |
.apple-control | Control | Custom styled checkbox/radio visual |
.apple-label | Label | Text label for the input |
data-max | Attribute | Limits checkbox selections in a group |
Form Integration
Native inputs are preserved for proper form submission. Use standard name
and value attributes for form processing.
<form action="/submit" method="POST">
<div class="apple-input-group">
<label class="apple-input-wrapper apple-checkbox">
<input type="checkbox" name="preferences[]" value="newsletter">
<span class="apple-control"></span>
<span class="apple-label">Subscribe to newsletter</span>
</label>
</div>
<button type="submit">Save</button>
</form>
Accessibility
- Use proper
<label>elements to wrap inputs for screen readers - Native inputs remain focusable and keyboard accessible
- Disabled states are properly communicated to assistive technologies
- Use semantic
nameattributes for form grouping - Radio buttons with the same
nameare automatically grouped
Common Use Cases
- Terms and conditions agreements
- Feature preference selection
- Multi-step form options
- Settings panels
- Survey and questionnaire forms
- Subscription plan selection
Browser Support
Works in all modern browsers. The custom styling is a progressive enhancement over native browser checkboxes and radio buttons.