Custom Checkboxes & Radios ☑️
Create beautiful, accessible, and interactive custom checkboxes and radio buttons with modern CSS techniques.
Why Custom Checkboxes & Radios Matter
Custom checkboxes and radio buttons enhance user experience by providing consistent styling across browsers, better visual feedback, and improved accessibility. They allow for creative designs while maintaining functionality.
🎨 Consistent Styling
Uniform appearance across all browsers and devices
♿ Accessibility
Proper focus states and screen reader support
📱 Better UX
Enhanced visual feedback and interaction
Basic Custom Checkboxes & Radios
Key Concepts:
- Hide native input with
display: none - Style custom indicator with CSS pseudo-elements
- Use
:checkedpseudo-class for states - Implement proper focus and hover states
- Ensure accessibility with ARIA attributes
Basic Custom Inputs Demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Custom Checkboxes & Radios</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', sans-serif;
line-height: 1.6;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 2rem;
}
.container {
max-width: 1000px;
margin: 0 auto;
background: white;
border-radius: 20px;
padding: 3rem;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
}
h1 {
color: #2d3748;
margin-bottom: 2rem;
text-align: center;
font-size: 2.5rem;
}
.input-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
margin: 2rem 0;
}
.input-group {
padding: 2rem;
background: #f8fafc;
border-radius: 12px;
border: 1px solid #e2e8f0;
}
.input-title {
font-weight: 600;
color: #2d3748;
margin-bottom: 1.5rem;
font-size: 1.2rem;
}
/* Base Custom Checkbox */
.custom-checkbox {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
cursor: pointer;
padding: 0.75rem;
border-radius: 8px;
transition: all 0.3s ease;
}
.custom-checkbox:hover {
background: #f1f5f9;
}
.custom-checkbox input {
display: none;
}
.checkmark {
width: 24px;
height: 24px;
border: 2px solid #cbd5e0;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
position: relative;
}
.custom-checkbox input:checked + .checkmark {
background: #3b82f6;
border-color: #3b82f6;
}
.custom-checkbox input:checked + .checkmark::after {
content: "✓";
color: white;
font-weight: bold;
font-size: 0.875rem;
}
/* Base Custom Radio */
.custom-radio {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
cursor: pointer;
padding: 0.75rem;
border-radius: 8px;
transition: all 0.3s ease;
}
.custom-radio:hover {
background: #f1f5f9;
}
.custom-radio input {
display: none;
}
.radio-dot {
width: 24px;
height: 24px;
border: 2px solid #cbd5e0;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
position: relative;
}
.custom-radio input:checked + .radio-dot {
border-color: #3b82f6;
}
.custom-radio input:checked + .radio-dot::after {
content: "";
width: 12px;
height: 12px;
background: #3b82f6;
border-radius: 50%;
}
/* Color Variants */
.checkbox-success input:checked + .checkmark {
background: #10b981;
border-color: #10b981;
}
.checkbox-warning input:checked + .checkmark {
background: #f59e0b;
border-color: #f59e0b;
}
.checkbox-danger input:checked + .checkmark {
background: #ef4444;
border-color: #ef4444;
}
.radio-success input:checked + .radio-dot {
border-color: #10b981;
}
.radio-success input:checked + .radio-dot::after {
background: #10b981;
}
.radio-warning input:checked + .radio-dot {
border-color: #f59e0b;
}
.radio-warning input:checked + .radio-dot::after {
background: #f59e0b;
}
.radio-danger input:checked + .radio-dot {
border-color: #ef4444;
}
.radio-danger input:checked + .radio-dot::after {
background: #ef4444;
}
/* Sizes */
.checkbox-sm .checkmark {
width: 20px;
height: 20px;
}
.checkbox-lg .checkmark {
width: 28px;
height: 28px;
}
.radio-sm .radio-dot {
width: 20px;
height: 20px;
}
.radio-sm .radio-dot::after {
width: 10px;
height: 10px;
}
.radio-lg .radio-dot {
width: 28px;
height: 28px;
}
.radio-lg .radio-dot::after {
width: 14px;
height: 14px;
}
/* Disabled State */
.custom-checkbox.disabled,
.custom-radio.disabled {
opacity: 0.6;
cursor: not-allowed;
}
.custom-checkbox.disabled:hover,
.custom-radio.disabled:hover {
background: transparent;
}
/* Focus States */
.custom-checkbox input:focus + .checkmark,
.custom-radio input:focus + .radio-dot {
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
border-color: #3b82f6;
}
/* Demo Section */
.demo-section {
background: #f8fafc;
padding: 2rem;
border-radius: 15px;
margin: 2rem 0;
border-left: 4px solid #667eea;
}
.code-example {
background: #2d3748;
color: #81e6d9;
padding: 1rem;
border-radius: 8px;
font-family: monospace;
margin: 1rem 0;
font-size: 0.9rem;
}
</style>
</head>
<body>
<div class="container">
<h1>☑️ Custom Checkboxes & Radios</h1>
<div class="demo-section">
<h2>Basic Custom Checkboxes</h2>
<div class="code-example">
/* Custom Checkbox Structure */<br>
<label class="custom-checkbox"><br>
<input type="checkbox"><br>
<span class="checkmark"></span><br>
Checkbox Label<br>
</label>
</div>
<div class="input-grid">
<div class="input-group">
<div class="input-title">Default Checkboxes</div>
<label class="custom-checkbox">
<input type="checkbox" checked>
<span class="checkmark"></span>
Default Checkbox
</label>
<label class="custom-checkbox">
<input type="checkbox">
<span class="checkmark"></span>
Unchecked State
</label>
<label class="custom-checkbox disabled">
<input type="checkbox" disabled>
<span class="checkmark"></span>
Disabled Checkbox
</label>
</div>
<div class="input-group">
<div class="input-title">Color Variants</div>
<label class="custom-checkbox checkbox-success">
<input type="checkbox" checked>
<span class="checkmark"></span>
Success Checkbox
</label>
<label class="custom-checkbox checkbox-warning">
<input type="checkbox" checked>
<span class="checkmark"></span>
Warning Checkbox
</label>
<label class="custom-checkbox checkbox-danger">
<input type="checkbox" checked>
<span class="checkmark"></span>
Danger Checkbox
</label>
</div>
<div class="input-group">
<div class="input-title">Size Variants</div>
<label class="custom-checkbox checkbox-sm">
<input type="checkbox" checked>
<span class="checkmark"></span>
Small Checkbox
</label>
<label class="custom-checkbox">
<input type="checkbox" checked>
<span class="checkmark"></span>
Default Checkbox
</label>
<label class="custom-checkbox checkbox-lg">
<input type="checkbox" checked>
<span class="checkmark"></span>
Large Checkbox
</label>
</div>
</div>
</div>
<div class="demo-section">
<h2>Basic Custom Radio Buttons</h2>
<div class="code-example">
/* Custom Radio Structure */<br>
<label class="custom-radio"><br>
<input type="radio" name="group"><br>
<span class="radio-dot"></span><br>
Radio Label<br>
</label>
</div>
<div class="input-grid">
<div class="input-group">
<div class="input-title">Default Radio Group</div>
<label class="custom-radio">
<input type="radio" name="basic-radio" checked>
<span class="radio-dot"></span>
Option 1
</label>
<label class="custom-radio">
<input type="radio" name="basic-radio">
<span class="radio-dot"></span>
Option 2
</label>
<label class="custom-radio disabled">
<input type="radio" name="basic-radio" disabled>
<span class="radio-dot"></span>
Disabled Option
</label>
</div>
<div class="input-group">
<div class="input-title">Color Variants</div>
<label class="custom-radio radio-success">
<input type="radio" name="color-radio" checked>
<span class="radio-dot"></span>
Success Radio
</label>
<label class="custom-radio radio-warning">
<input type="radio" name="color-radio">
<span class="radio-dot"></span>
Warning Radio
</label>
<label class="custom-radio radio-danger">
<input type="radio" name="color-radio">
<span class="radio-dot"></span>
Danger Radio
</label>
</div>
<div class="input-group">
<div class="input-title">Size Variants</div>
<label class="custom-radio radio-sm">
<input type="radio" name="size-radio" checked>
<span class="radio-dot"></span>
Small Radio
</label>
<label class="custom-radio">
<input type="radio" name="size-radio">
<span class="radio-dot"></span>
Default Radio
</label>
<label class="custom-radio radio-lg">
<input type="radio" name="size-radio">
<span class="radio-dot"></span>
Large Radio
</label>
</div>
</div>
</div>
<div class="demo-section">
<h2>Checkbox & Radio Groups</h2>
<div class="code-example">
/* Group Layout */<br>
Use fieldset and legend for groups<br>
Consistent spacing and alignment<br>
Clear visual hierarchy
</div>
<div class="input-grid">
<div class="input-group">
<div class="input-title">Checkbox Group</div>
<fieldset style="border: none; padding: 0;">
<legend style="font-weight: 600; margin-bottom: 1rem; color: #374151;">
Select your interests:
</legend>
<label class="custom-checkbox">
<input type="checkbox" name="interests" value="technology">
<span class="checkmark"></span>
Technology
</label>
<label class="custom-checkbox">
<input type="checkbox" name="interests" value="sports">
<span class="checkmark"></span>
Sports
</label>
<label class="custom-checkbox">
<input type="checkbox" name="interests" value="music">
<span class="checkmark"></span>
Music
</label>
<label class="custom-checkbox">
<input type="checkbox" name="interests" value="travel">
<span class="checkmark"></span>
Travel
</label>
</fieldset>
</div>
<div class="input-group">
<div class="input-title">Radio Group</div>
<fieldset style="border: none; padding: 0;">
<legend style="font-weight: 600; margin-bottom: 1rem; color: #374151;">
Choose your plan:
</legend>
<label class="custom-radio">
<input type="radio" name="plan" value="basic" checked>
<span class="radio-dot"></span>
Basic Plan
</label>
<label class="custom-radio">
<input type="radio" name="plan" value="pro">
<span class="radio-dot"></span>
Pro Plan
</label>
<label class="custom-radio">
<input type="radio" name="plan" value="enterprise">
<span class="radio-dot"></span>
Enterprise Plan
</label>
</fieldset>
</div>
</div>
</div>
</div>
<script>
// Add interactive functionality
const checkboxes = document.querySelectorAll('.custom-checkbox:not(.disabled)');
const radios = document.querySelectorAll('.custom-radio:not(.disabled)');
// Add click feedback
checkboxes.forEach(checkbox => {
checkbox.addEventListener('click', function() {
this.style.transform = 'scale(0.98)';
setTimeout(() => {
this.style.transform = 'scale(1)';
}, 150);
});
});
radios.forEach(radio => {
radio.addEventListener('click', function() {
this.style.transform = 'scale(0.98)';
setTimeout(() => {
this.style.transform = 'scale(1)';
}, 150);
});
});
// Demo form submission
const form = document.createElement('form');
form.style.marginTop = '2rem';
form.innerHTML = `
<div class="demo-section">
<h2>Interactive Demo</h2>
<p style="margin-bottom: 1rem; color: #6b7280;">
Select options and see the values below:
</p>
<div id="demo-output" style="background: #e5e7eb; padding: 1rem; border-radius: 8px; font-family: monospace;"></div>
</div>
`;
document.querySelector('.container').appendChild(form);
function updateDemoOutput() {
const interests = Array.from(document.querySelectorAll('input[name="interests"]:checked'))
.map(input => input.value);
const plan = document.querySelector('input[name="plan"]:checked')?.value;
const output = `
Selected Interests: ${interests.join(', ') || 'None'}\n
Selected Plan: ${plan || 'None'}
`.trim();
document.getElementById('demo-output').textContent = output;
}
// Listen for changes
document.querySelectorAll('input[type="checkbox"], input[type="radio"]').forEach(input => {
input.addEventListener('change', updateDemoOutput);
});
// Initial update
updateDemoOutput();
</script>
</body>
</html>Advanced Custom Inputs
Visual Enhancements
Create engaging inputs with icons, animations, gradients, and card-based layouts that improve user interaction.
Interactive Features
Implement toggle switches, hover effects, and real-time feedback that make forms more intuitive and engaging.
Advanced Inputs Demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Advanced Custom Inputs</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', sans-serif;
line-height: 1.6;
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
min-height: 100vh;
padding: 2rem;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
border-radius: 20px;
padding: 3rem;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
}
h1 {
color: #2d3748;
margin-bottom: 2rem;
text-align: center;
font-size: 2.5rem;
}
.input-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
margin: 2rem 0;
}
.input-group {
padding: 2rem;
background: #f8fafc;
border-radius: 12px;
border: 1px solid #e2e8f0;
}
.input-title {
font-weight: 600;
color: #2d3748;
margin-bottom: 1.5rem;
font-size: 1.2rem;
}
/* Icon Checkboxes */
.checkbox-icon {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
cursor: pointer;
padding: 1rem;
border: 2px solid #e5e7eb;
border-radius: 12px;
transition: all 0.3s ease;
}
.checkbox-icon:hover {
border-color: #3b82f6;
transform: translateY(-2px);
}
.checkbox-icon input {
display: none;
}
.checkbox-icon input:checked + .icon-wrapper {
background: #3b82f6;
color: white;
border-color: #3b82f6;
}
.icon-wrapper {
width: 48px;
height: 48px;
border: 2px solid #e5e7eb;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
transition: all 0.3s ease;
}
.icon-content {
flex: 1;
}
.icon-title {
font-weight: 600;
margin-bottom: 0.25rem;
}
.icon-description {
font-size: 0.875rem;
color: #6b7280;
}
/* Toggle Switch */
.toggle-switch {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
cursor: pointer;
padding: 1rem;
border-radius: 8px;
transition: all 0.3s ease;
}
.toggle-switch:hover {
background: #f1f5f9;
}
.toggle-switch input {
display: none;
}
.toggle-slider {
width: 60px;
height: 30px;
background: #cbd5e0;
border-radius: 15px;
position: relative;
transition: all 0.3s ease;
}
.toggle-slider::before {
content: "";
position: absolute;
width: 26px;
height: 26px;
background: white;
border-radius: 50%;
top: 2px;
left: 2px;
transition: all 0.3s ease;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.toggle-switch input:checked + .toggle-slider {
background: #3b82f6;
}
.toggle-switch input:checked + .toggle-slider::before {
transform: translateX(30px);
}
/* Animated Checkbox */
.checkbox-animated {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
cursor: pointer;
padding: 1rem;
border-radius: 8px;
transition: all 0.3s ease;
}
.checkbox-animated:hover {
background: #f1f5f9;
}
.checkbox-animated input {
display: none;
}
.animated-checkmark {
width: 24px;
height: 24px;
border: 2px solid #cbd5e0;
border-radius: 6px;
position: relative;
transition: all 0.3s ease;
}
.checkbox-animated input:checked + .animated-checkmark {
background: #3b82f6;
border-color: #3b82f6;
animation: checkmarkPop 0.3s ease;
}
.checkbox-animated input:checked + .animated-checkmark::after {
content: "";
position: absolute;
left: 7px;
top: 3px;
width: 6px;
height: 12px;
border: solid white;
border-width: 0 2px 2px 0;
transform: rotate(45deg);
animation: checkmarkDraw 0.3s ease;
}
@keyframes checkmarkPop {
0% { transform: scale(1); }
50% { transform: scale(1.2); }
100% { transform: scale(1); }
}
@keyframes checkmarkDraw {
0% { opacity: 0; transform: rotate(45deg) scale(0); }
50% { opacity: 1; transform: rotate(45deg) scale(1.2); }
100% { opacity: 1; transform: rotate(45deg) scale(1); }
}
/* Card Style Radio */
.radio-card {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
cursor: pointer;
padding: 1.5rem;
border: 2px solid #e5e7eb;
border-radius: 12px;
transition: all 0.3s ease;
}
.radio-card:hover {
border-color: #3b82f6;
transform: translateY(-2px);
}
.radio-card input {
display: none;
}
.radio-card input:checked + .card-content {
border-color: #3b82f6;
background: #eff6ff;
}
.card-content {
display: flex;
align-items: center;
gap: 1rem;
width: 100%;
transition: all 0.3s ease;
}
.card-icon {
width: 40px;
height: 40px;
background: #3b82f6;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 1.25rem;
}
.card-text {
flex: 1;
}
.card-title {
font-weight: 600;
margin-bottom: 0.25rem;
}
.card-description {
font-size: 0.875rem;
color: #6b7280;
}
/* Gradient Checkbox */
.checkbox-gradient {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
cursor: pointer;
padding: 1rem;
border-radius: 8px;
transition: all 0.3s ease;
}
.checkbox-gradient input {
display: none;
}
.gradient-checkmark {
width: 24px;
height: 24px;
border: 2px solid #cbd5e0;
border-radius: 6px;
position: relative;
transition: all 0.3s ease;
background: linear-gradient(135deg, #667eea, #764ba2);
opacity: 0;
}
.checkbox-gradient input:checked + .gradient-checkmark {
opacity: 1;
animation: gradientGlow 1.5s ease-in-out infinite alternate;
}
.checkbox-gradient input:checked + .gradient-checkmark::after {
content: "✓";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-weight: bold;
font-size: 0.875rem;
}
@keyframes gradientGlow {
from {
box-shadow: 0 0 10px rgba(102, 126, 234, 0.5);
}
to {
box-shadow: 0 0 20px rgba(102, 126, 234, 0.8);
}
}
/* Neumorphism Style */
.checkbox-neumorphism {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
cursor: pointer;
padding: 1rem;
border-radius: 12px;
transition: all 0.3s ease;
}
.checkbox-neumorphism input {
display: none;
}
.neumorphism-checkmark {
width: 24px;
height: 24px;
border-radius: 6px;
background: #f0f0f0;
box-shadow: 5px 5px 10px #d9d9d9,
-5px -5px 10px #ffffff;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}
.checkbox-neumorphism input:checked + .neumorphism-checkmark {
box-shadow: inset 5px 5px 10px #d9d9d9,
inset -5px -5px 10px #ffffff;
color: #3b82f6;
}
.checkbox-neumorphism input:checked + .neumorphism-checkmark::after {
content: "✓";
font-weight: bold;
}
/* Demo Section */
.demo-section {
background: #f8fafc;
padding: 2rem;
border-radius: 15px;
margin: 2rem 0;
border-left: 4px solid #4facfe;
}
.code-example {
background: #2d3748;
color: #81e6d9;
padding: 1rem;
border-radius: 8px;
font-family: monospace;
margin: 1rem 0;
font-size: 0.9rem;
}
</style>
</head>
<body>
<div class="container">
<h1>🚀 Advanced Custom Inputs</h1>
<div class="demo-section">
<h2>Icon Checkboxes</h2>
<div class="code-example">
/* Checkbox with Icons */<br>
Visual representation with icons<br>
Enhanced user experience<br>
Better content organization
</div>
<div class="input-grid">
<div class="input-group">
<div class="input-title">Feature Selection</div>
<label class="checkbox-icon">
<input type="checkbox" name="features" value="security">
<div class="icon-wrapper">🔒</div>
<div class="icon-content">
<div class="icon-title">Security</div>
<div class="icon-description">Advanced security features</div>
</div>
</label>
<label class="checkbox-icon">
<input type="checkbox" name="features" value="performance" checked>
<div class="icon-wrapper">⚡</div>
<div class="icon-content">
<div class="icon-title">Performance</div>
<div class="icon-description">High performance optimization</div>
</div>
</label>
<label class="checkbox-icon">
<input type="checkbox" name="features" value="support">
<div class="icon-wrapper">🎧</div>
<div class="icon-content">
<div class="icon-title">Support</div>
<div class="icon-description">24/7 customer support</div>
</div>
</label>
</div>
</div>
</div>
<div class="demo-section">
<h2>Toggle Switches</h2>
<div class="code-example">
/* Toggle Switch Implementation */<br>
Slider-based toggle<br>
Smooth animations<br>
Mobile-friendly design
</div>
<div class="input-grid">
<div class="input-group">
<div class="input-title">Settings</div>
<label class="toggle-switch">
<input type="checkbox" checked>
<span class="toggle-slider"></span>
<span>Enable Notifications</span>
</label>
<label class="toggle-switch">
<input type="checkbox">
<span class="toggle-slider"></span>
<span>Dark Mode</span>
</label>
<label class="toggle-switch">
<input type="checkbox" checked>
<span class="toggle-slider"></span>
<span>Auto-update</span>
</label>
</div>
<div class="input-group">
<div class="input-title">Animated Checkbox</div>
<label class="checkbox-animated">
<input type="checkbox" checked>
<span class="animated-checkmark"></span>
<span>Animated Checkbox</span>
</label>
<label class="checkbox-animated">
<input type="checkbox">
<span class="animated-checkmark"></span>
<span>Another Option</span>
</label>
</div>
</div>
</div>
<div class="demo-section">
<h2>Card Style Inputs</h2>
<div class="code-example">
/* Card-based Selection */<br>
Enhanced visual design<br>
Better content organization<br>
Improved user engagement
</div>
<div class="input-grid">
<div class="input-group">
<div class="input-title">Plan Selection</div>
<label class="radio-card">
<input type="radio" name="plan-type" value="basic" checked>
<div class="card-content">
<div class="card-icon">💰</div>
<div class="card-text">
<div class="card-title">Basic Plan</div>
<div class="card-description">Perfect for individuals</div>
</div>
</div>
</label>
<label class="radio-card">
<input type="radio" name="plan-type" value="pro">
<div class="card-content">
<div class="card-icon">🚀</div>
<div class="card-text">
<div class="card-title">Pro Plan</div>
<div class="card-description">Great for small teams</div>
</div>
</div>
</label>
<label class="radio-card">
<input type="radio" name="plan-type" value="enterprise">
<div class="card-content">
<div class="card-icon">🏢</div>
<div class="card-text">
<div class="card-title">Enterprise</div>
<div class="card-description">For large organizations</div>
</div>
</div>
</label>
</div>
</div>
</div>
<div class="demo-section">
<h2>Special Effects</h2>
<div class="code-example">
/* Advanced Visual Effects */<br>
Gradient backgrounds<br>
Neumorphism design<br>
Smooth animations
</div>
<div class="input-grid">
<div class="input-group">
<div class="input-title">Gradient Checkbox</div>
<label class="checkbox-gradient">
<input type="checkbox" checked>
<span class="gradient-checkmark"></span>
<span>Gradient Style</span>
</label>
<label class="checkbox-gradient">
<input type="checkbox">
<span class="gradient-checkmark"></span>
<span>Another Option</span>
</label>
</div>
<div class="input-group">
<div class="input-title">Neumorphism</div>
<label class="checkbox-neumorphism">
<input type="checkbox" checked>
<span class="neumorphism-checkmark"></span>
<span>Neumorphism Style</span>
</label>
<label class="checkbox-neumorphism">
<input type="checkbox">
<span class="neumorphism-checkmark"></span>
<span>Soft UI Design</span>
</label>
</div>
</div>
</div>
</div>
<script>
// Interactive functionality for advanced inputs
const toggleSwitches = document.querySelectorAll('.toggle-switch input');
const iconCheckboxes = document.querySelectorAll('.checkbox-icon');
const radioCards = document.querySelectorAll('.radio-card');
// Toggle switch feedback
toggleSwitches.forEach(toggle => {
toggle.addEventListener('change', function() {
const label = this.parentElement;
label.style.transform = 'scale(0.98)';
setTimeout(() => {
label.style.transform = 'scale(1)';
}, 150);
console.log(`Toggle ${this.checked ? 'enabled' : 'disabled'}: ${label.textContent.trim()}`);
});
});
// Icon checkbox hover effects
iconCheckboxes.forEach(checkbox => {
checkbox.addEventListener('mouseenter', function() {
this.style.transform = 'translateY(-2px)';
});
checkbox.addEventListener('mouseleave', function() {
this.style.transform = 'translateY(0)';
});
});
// Radio card selection feedback
radioCards.forEach(card => {
card.addEventListener('click', function() {
// Remove checked state from all cards in group
const groupName = this.querySelector('input').name;
document.querySelectorAll(`input[name="${groupName}"]`).forEach(input => {
input.checked = false;
});
// Set current card as checked
this.querySelector('input').checked = true;
console.log(`Selected: ${this.querySelector('.card-title').textContent}`);
});
});
// Demo output for advanced inputs
const advancedForm = document.createElement('div');
advancedForm.innerHTML = `
<div class="demo-section">
<h2>Interactive Demo</h2>
<p style="margin-bottom: 1rem; color: #6b7280;">
See how your selections update in real-time:
</p>
<div id="advanced-output" style="background: #e5e7eb; padding: 1rem; border-radius: 8px; font-family: monospace; min-height: 80px;"></div>
</div>
`;
document.querySelector('.container').appendChild(advancedForm);
function updateAdvancedOutput() {
const features = Array.from(document.querySelectorAll('input[name="features"]:checked'))
.map(input => input.value);
const planType = document.querySelector('input[name="plan-type"]:checked')?.value;
const notifications = document.querySelector('.toggle-switch input[type="checkbox"]')?.checked;
const output = `
Selected Features: ${features.join(', ') || 'None'}\n
Selected Plan: ${planType || 'None'}\n
Notifications: ${notifications ? 'Enabled' : 'Disabled'}
`.trim();
document.getElementById('advanced-output').textContent = output;
}
// Listen for changes on all advanced inputs
document.querySelectorAll('.checkbox-icon input, .toggle-switch input, .radio-card input, .checkbox-animated input, .checkbox-gradient input, .checkbox-neumorphism input').forEach(input => {
input.addEventListener('change', updateAdvancedOutput);
});
// Initial update
updateAdvancedOutput();
</script>
</body>
</html>Mobile-Optimized Custom Inputs
Touch-Friendly Design
Mobile devices require larger touch targets (44px+), appropriate spacing, and visual feedback that works well on touch screens with proper focus management.
Mobile-Optimized Demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mobile-Optimized Custom Inputs</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', sans-serif;
line-height: 1.6;
background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%);
min-height: 100vh;
padding: 1rem;
}
.container {
max-width: 400px;
margin: 0 auto;
background: white;
border-radius: 20px;
padding: 2rem;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
}
h1 {
color: #2d3748;
margin-bottom: 1.5rem;
text-align: center;
font-size: 1.8rem;
}
.input-group {
margin-bottom: 2rem;
padding: 1.5rem;
background: #f8fafc;
border-radius: 12px;
border: 1px solid #e2e8f0;
}
.input-title {
font-weight: 600;
color: #2d3748;
margin-bottom: 1rem;
font-size: 1.1rem;
}
/* Mobile-Optimized Checkbox */
.mobile-checkbox {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 0.75rem;
cursor: pointer;
padding: 1rem;
border-radius: 12px;
transition: all 0.2s ease;
min-height: 60px;
-webkit-tap-highlight-color: transparent;
touch-action: manipulation;
}
.mobile-checkbox:active {
background: #f1f5f9;
transform: scale(0.98);
}
.mobile-checkbox input {
display: none;
}
.mobile-checkmark {
width: 28px;
height: 28px;
border: 2px solid #cbd5e0;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
flex-shrink: 0;
}
.mobile-checkbox input:checked + .mobile-checkmark {
background: #3b82f6;
border-color: #3b82f6;
}
.mobile-checkbox input:checked + .mobile-checkmark::after {
content: "✓";
color: white;
font-weight: bold;
font-size: 1rem;
}
/* Mobile-Optimized Radio */
.mobile-radio {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 0.75rem;
cursor: pointer;
padding: 1rem;
border-radius: 12px;
transition: all 0.2s ease;
min-height: 60px;
-webkit-tap-highlight-color: transparent;
touch-action: manipulation;
}
.mobile-radio:active {
background: #f1f5f9;
transform: scale(0.98);
}
.mobile-radio input {
display: none;
}
.mobile-radio-dot {
width: 28px;
height: 28px;
border: 2px solid #cbd5e0;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
flex-shrink: 0;
}
.mobile-radio input:checked + .mobile-radio-dot {
border-color: #3b82f6;
}
.mobile-radio input:checked + .mobile-radio-dot::after {
content: "";
width: 14px;
height: 14px;
background: #3b82f6;
border-radius: 50%;
}
/* Mobile Toggle Switch */
.mobile-toggle {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 0.75rem;
cursor: pointer;
padding: 1rem;
border-radius: 12px;
transition: all 0.2s ease;
min-height: 60px;
-webkit-tap-highlight-color: transparent;
touch-action: manipulation;
}
.mobile-toggle:active {
background: #f1f5f9;
}
.mobile-toggle input {
display: none;
}
.mobile-toggle-slider {
width: 52px;
height: 28px;
background: #cbd5e0;
border-radius: 14px;
position: relative;
transition: all 0.2s ease;
flex-shrink: 0;
}
.mobile-toggle-slider::before {
content: "";
position: absolute;
width: 24px;
height: 24px;
background: white;
border-radius: 50%;
top: 2px;
left: 2px;
transition: all 0.2s ease;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.mobile-toggle input:checked + .mobile-toggle-slider {
background: #3b82f6;
}
.mobile-toggle input:checked + .mobile-toggle-slider::before {
transform: translateX(24px);
}
/* Card Style for Mobile */
.mobile-card {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 0.75rem;
cursor: pointer;
padding: 1.25rem;
border: 2px solid #e5e7eb;
border-radius: 16px;
transition: all 0.2s ease;
min-height: 80px;
-webkit-tap-highlight-color: transparent;
touch-action: manipulation;
}
.mobile-card:active {
border-color: #3b82f6;
transform: scale(0.98);
}
.mobile-card input {
display: none;
}
.mobile-card input:checked + .card-wrapper {
border-color: #3b82f6;
background: #eff6ff;
}
.card-wrapper {
display: flex;
align-items: center;
gap: 1rem;
width: 100%;
transition: all 0.2s ease;
}
.mobile-card-icon {
width: 44px;
height: 44px;
background: #3b82f6;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 1.25rem;
flex-shrink: 0;
}
.mobile-card-text {
flex: 1;
}
.mobile-card-title {
font-weight: 600;
margin-bottom: 0.25rem;
font-size: 1rem;
}
.mobile-card-description {
font-size: 0.875rem;
color: #6b7280;
}
/* Focus States for Accessibility */
.mobile-checkbox:focus-within,
.mobile-radio:focus-within,
.mobile-toggle:focus-within,
.mobile-card:focus-within {
outline: 2px solid #3b82f6;
outline-offset: 2px;
}
/* Responsive Adjustments */
@media (max-width: 480px) {
.container {
padding: 1.5rem;
margin: 0.5rem;
}
h1 {
font-size: 1.5rem;
}
.input-group {
padding: 1.25rem;
}
.mobile-checkbox,
.mobile-radio,
.mobile-toggle,
.mobile-card {
padding: 0.875rem;
}
}
/* High Contrast Support */
@media (prefers-contrast: high) {
.mobile-checkmark,
.mobile-radio-dot,
.mobile-toggle-slider {
border-width: 3px;
}
}
/* Reduced Motion Support */
@media (prefers-reduced-motion: reduce) {
.mobile-checkbox,
.mobile-radio,
.mobile-toggle,
.mobile-card {
transition: none;
}
.mobile-checkbox:active,
.mobile-radio:active,
.mobile-card:active {
transform: none;
}
}
/* Demo Section */
.demo-section {
background: #f8fafc;
padding: 1.5rem;
border-radius: 12px;
margin: 1.5rem 0;
border-left: 4px solid #ff9a9e;
}
.code-example {
background: #2d3748;
color: #81e6d9;
padding: 1rem;
border-radius: 8px;
font-family: monospace;
margin: 1rem 0;
font-size: 0.8rem;
}
</style>
</head>
<body>
<div class="container">
<h1>📱 Mobile Custom Inputs</h1>
<div class="demo-section">
<h2>Mobile Checkboxes</h2>
<div class="code-example">
/* Mobile-optimized checkboxes */<br>
Larger touch targets (60px+)<br>
Clear visual feedback<br>
Accessible design
</div>
<div class="input-group">
<div class="input-title">Preferences</div>
<label class="mobile-checkbox">
<input type="checkbox" checked>
<span class="mobile-checkmark"></span>
<span>Email Notifications</span>
</label>
<label class="mobile-checkbox">
<input type="checkbox">
<span class="mobile-checkmark"></span>
<span>SMS Notifications</span>
</label>
<label class="mobile-checkbox">
<input type="checkbox" checked>
<span class="mobile-checkmark"></span>
<span>Push Notifications</span>
</label>
</div>
</div>
<div class="demo-section">
<h2>Mobile Radio Buttons</h2>
<div class="code-example">
/* Mobile radio groups */<br>
Easy thumb selection<br>
Clear selected state<br>
Grouped layout
</div>
<div class="input-group">
<div class="input-title">Delivery Option</div>
<label class="mobile-radio">
<input type="radio" name="delivery" checked>
<span class="mobile-radio-dot"></span>
<span>Standard Delivery (3-5 days)</span>
</label>
<label class="mobile-radio">
<input type="radio" name="delivery">
<span class="mobile-radio-dot"></span>
<span>Express Delivery (1-2 days)</span>
</label>
<label class="mobile-radio">
<input type="radio" name="delivery">
<span class="mobile-radio-dot"></span>
<span>Same Day Delivery</span>
</label>
</div>
</div>
<div class="demo-section">
<h2>Mobile Toggle Switches</h2>
<div class="code-example">
/* Touch-friendly toggles */<br>
Thumb-friendly size<br>
Instant visual feedback<br>
Smooth transitions
</div>
<div class="input-group">
<div class="input-title">App Settings</div>
<label class="mobile-toggle">
<span>Dark Mode</span>
<input type="checkbox" checked>
<span class="mobile-toggle-slider"></span>
</label>
<label class="mobile-toggle">
<span>Location Services</span>
<input type="checkbox">
<span class="mobile-toggle-slider"></span>
</label>
<label class="mobile-toggle">
<span>Auto-sync</span>
<input type="checkbox" checked>
<span class="mobile-toggle-slider"></span>
</label>
</div>
</div>
<div class="demo-section">
<h2>Card Selection</h2>
<div class="code-example">
/* Card-based inputs */<br>
Enhanced visual design<br>
Better content organization<br>
Improved touch targets
</div>
<div class="input-group">
<div class="input-title">Payment Method</div>
<label class="mobile-card">
<input type="radio" name="payment" checked>
<div class="card-wrapper">
<div class="mobile-card-icon">💳</div>
<div class="mobile-card-text">
<div class="mobile-card-title">Credit Card</div>
<div class="mobile-card-description">Pay with your credit card</div>
</div>
</div>
</label>
<label class="mobile-card">
<input type="radio" name="payment">
<div class="card-wrapper">
<div class="mobile-card-icon">📱</div>
<div class="mobile-card-text">
<div class="mobile-card-title">Mobile Payment</div>
<div class="mobile-card-description">Apple Pay, Google Pay</div>
</div>
</div>
</label>
<label class="mobile-card">
<input type="radio" name="payment">
<div class="card-wrapper">
<div class="mobile-card-icon">🏦</div>
<div class="mobile-card-text">
<div class="mobile-card-title">Bank Transfer</div>
<div class="mobile-card-description">Direct bank transfer</div>
</div>
</div>
</label>
</div>
</div>
<div class="demo-section">
<h2>Form Example</h2>
<div class="code-example">
/* Complete mobile form */<br>
Combined input types<br>
Consistent styling<br>
Mobile-optimized layout
</div>
<div class="input-group">
<div class="input-title">Account Setup</div>
<label class="mobile-checkbox" style="margin-bottom: 1.5rem;">
<input type="checkbox" checked>
<span class="mobile-checkmark"></span>
<span>I agree to the terms and conditions</span>
</label>
<div style="margin-bottom: 1.5rem;">
<div style="font-weight: 600; margin-bottom: 0.75rem; color: #374151;">
Subscription Type:
</div>
<label class="mobile-radio">
<input type="radio" name="subscription" checked>
<span class="mobile-radio-dot"></span>
<span>Monthly</span>
</label>
<label class="mobile-radio">
<input type="radio" name="subscription">
<span class="mobile-radio-dot"></span>
<span>Yearly (Save 20%)</span>
</label>
</div>
<label class="mobile-toggle">
<span>Enable automatic renewal</span>
<input type="checkbox" checked>
<span class="mobile-toggle-slider"></span>
</label>
</div>
</div>
</div>
<script>
// Mobile-specific interactions
const mobileInputs = document.querySelectorAll('.mobile-checkbox, .mobile-radio, .mobile-toggle, .mobile-card');
// Add touch feedback
mobileInputs.forEach(input => {
input.addEventListener('touchstart', function() {
this.style.transform = 'scale(0.98)';
});
input.addEventListener('touchend', function() {
this.style.transform = 'scale(1)';
});
});
// Form submission demo
const mobileForm = document.createElement('div');
mobileForm.innerHTML = `
<div class="demo-section">
<h2>Live Preview</h2>
<p style="margin-bottom: 1rem; color: #6b7280;">
Your selected options will appear here:
</p>
<div id="mobile-output" style="background: #e5e7eb; padding: 1rem; border-radius: 8px; font-family: monospace; min-height: 100px; font-size: 0.9rem;"></div>
</div>
`;
document.querySelector('.container').appendChild(mobileForm);
function updateMobileOutput() {
const notifications = Array.from(document.querySelectorAll('.mobile-checkbox input:checked'))
.map(input => input.parentElement.textContent.trim());
const delivery = document.querySelector('input[name="delivery"]:checked')?.parentElement.textContent.trim();
const payment = document.querySelector('input[name="payment"]:checked')?.parentElement.querySelector('.mobile-card-title').textContent;
const darkMode = document.querySelector('.mobile-toggle input[type="checkbox"]')?.checked;
const subscription = document.querySelector('input[name="subscription"]:checked')?.parentElement.textContent.trim();
const output = `
📧 Notifications: ${notifications.join(', ') || 'None'}\n
🚚 Delivery: ${delivery || 'Not selected'}\n
💳 Payment: ${payment || 'Not selected'}\n
🌙 Dark Mode: ${darkMode ? 'On' : 'Off'}\n
📅 Subscription: ${subscription || 'Not selected'}
`.trim();
document.getElementById('mobile-output').textContent = output;
}
// Listen for changes on all mobile inputs
document.querySelectorAll('.mobile-checkbox input, .mobile-radio input, .mobile-toggle input, .mobile-card input').forEach(input => {
input.addEventListener('change', updateMobileOutput);
});
// Initial update
updateMobileOutput();
// Prevent default form submission
document.querySelectorAll('input[type="checkbox"], input[type="radio"]').forEach(input => {
input.addEventListener('click', (e) => {
if (e.target.type === 'checkbox' || e.target.type === 'radio') {
e.preventDefault();
}
});
});
</script>
</body>
</html>Accessibility & Best Practices
🎯 Focus Management
Clear focus indicators and keyboard navigation
🌈 Color Contrast
WCAG compliant color ratios and states
📝 ARIA Attributes
Screen reader support and semantic HTML
Accessibility Demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Accessible Custom Inputs</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', sans-serif;
line-height: 1.6;
background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%);
min-height: 100vh;
padding: 2rem;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
border-radius: 20px;
padding: 3rem;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
}
h1 {
color: #2d3748;
margin-bottom: 2rem;
text-align: center;
font-size: 2.5rem;
}
.input-group {
margin-bottom: 2rem;
padding: 1.5rem;
background: #f8fafc;
border-radius: 12px;
border: 1px solid #e2e8f0;
}
.input-title {
font-weight: 600;
color: #2d3748;
margin-bottom: 1rem;
font-size: 1.1rem;
}
.accessibility-note {
background: #e6fffa;
border: 1px solid #81e6d9;
border-radius: 8px;
padding: 1rem;
margin: 1rem 0;
font-size: 0.9rem;
}
.accessibility-note.error {
background: #fed7d7;
border-color: #feb2b2;
}
/* Accessible Custom Checkbox */
.acc-checkbox {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
cursor: pointer;
padding: 1rem;
border-radius: 8px;
transition: all 0.3s ease;
border: 2px solid transparent;
}
.acc-checkbox:hover {
background: #f1f5f9;
}
.acc-checkbox input {
position: absolute;
opacity: 0;
width: 0;
height: 0;
}
.acc-checkmark {
width: 24px;
height: 24px;
border: 2px solid #4b5563;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
position: relative;
flex-shrink: 0;
}
.acc-checkbox input:checked + .acc-checkmark {
background: #1e40af;
border-color: #1e40af;
}
.acc-checkbox input:checked + .acc-checkmark::after {
content: "✓";
color: white;
font-weight: bold;
font-size: 0.875rem;
}
/* Focus States */
.acc-checkbox:focus-within {
outline: 3px solid #3b82f6;
outline-offset: 2px;
}
.acc-checkbox input:focus + .acc-checkmark {
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3);
}
/* Accessible Custom Radio */
.acc-radio {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
cursor: pointer;
padding: 1rem;
border-radius: 8px;
transition: all 0.3s ease;
border: 2px solid transparent;
}
.acc-radio:hover {
background: #f1f5f9;
}
.acc-radio input {
position: absolute;
opacity: 0;
width: 0;
height: 0;
}
.acc-radio-dot {
width: 24px;
height: 24px;
border: 2px solid #4b5563;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
position: relative;
flex-shrink: 0;
}
.acc-radio input:checked + .acc-radio-dot {
border-color: #1e40af;
}
.acc-radio input:checked + .acc-radio-dot::after {
content: "";
width: 12px;
height: 12px;
background: #1e40af;
border-radius: 50%;
}
.acc-radio:focus-within {
outline: 3px solid #3b82f6;
outline-offset: 2px;
}
/* High Contrast Support */
@media (prefers-contrast: high) {
.acc-checkmark,
.acc-radio-dot {
border-width: 3px;
}
.acc-checkbox input:checked + .acc-checkmark,
.acc-radio input:checked + .acc-radio-dot {
border-width: 4px;
}
}
/* Reduced Motion Support */
@media (prefers-reduced-motion: reduce) {
.acc-checkbox,
.acc-radio {
transition: none;
}
}
/* Screen Reader Only Text */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
/* Disabled States */
.acc-checkbox.disabled,
.acc-radio.disabled {
opacity: 0.6;
cursor: not-allowed;
}
.acc-checkbox.disabled:hover,
.acc-radio.disabled:hover {
background: transparent;
}
/* Demo Section */
.demo-section {
background: #f8fafc;
padding: 2rem;
border-radius: 15px;
margin: 2rem 0;
border-left: 4px solid #a8edea;
}
.code-example {
background: #2d3748;
color: #81e6d9;
padding: 1rem;
border-radius: 8px;
font-family: monospace;
margin: 1rem 0;
font-size: 0.9rem;
}
/* Color Contrast Demo */
.contrast-demo {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
margin: 1rem 0;
}
.contrast-good {
background: #1e40af;
color: white;
padding: 1rem;
border-radius: 8px;
text-align: center;
}
.contrast-bad {
background: #3b82f6;
color: #bfdbfe;
padding: 1rem;
border-radius: 8px;
text-align: center;
}
/* ARIA Examples */
.aria-example {
background: #fef3c7;
border: 1px solid #f59e0b;
border-radius: 8px;
padding: 1rem;
margin: 1rem 0;
}
</style>
</head>
<body>
<div class="container">
<h1>♿ Accessible Custom Inputs</h1>
<div class="demo-section">
<h2>Keyboard Navigation & Focus</h2>
<div class="code-example">
/* Focus Management */<br>
:focus-within for container focus<br>
outline-offset for better visibility<br>
High contrast focus indicators
</div>
<div class="accessibility-note">
✅ <strong>Good:</strong> Clear focus indicators help keyboard users understand which element is active.
</div>
<div class="input-group">
<div class="input-title">Try navigating with Tab key:</div>
<label class="acc-checkbox">
<input type="checkbox">
<span class="acc-checkmark"></span>
<span>First checkbox option</span>
</label>
<label class="acc-checkbox">
<input type="checkbox" checked>
<span class="acc-checkmark"></span>
<span>Second checkbox option</span>
</label>
<label class="acc-radio">
<input type="radio" name="demo-radio">
<span class="acc-radio-dot"></span>
<span>First radio option</span>
</label>
<label class="acc-radio">
<input type="radio" name="demo-radio" checked>
<span class="acc-radio-dot"></span>
<span>Second radio option</span>
</label>
</div>
</div>
<div class="demo-section">
<h2>Color Contrast & States</h2>
<div class="code-example">
/* WCAG Color Contrast */<br>
Minimum 4.5:1 for normal text<br>
3:1 for large text<br>
Proper checked and unchecked states
</div>
<div class="contrast-demo">
<div class="contrast-good">
<strong>Good Contrast</strong><br>
WCAG AA Compliant
</div>
<div class="contrast-bad">
<strong>Poor Contrast</strong><br>
Fails WCAG
</div>
</div>
<div class="accessibility-note error">
❌ <strong>Avoid:</strong> Low contrast ratios make it difficult for users with visual impairments to distinguish between states.
</div>
<div class="input-group">
<div class="input-title">Accessible Color Combinations</div>
<label class="acc-checkbox">
<input type="checkbox" checked>
<span class="acc-checkmark"></span>
<span>High contrast checkbox</span>
</label>
<label class="acc-radio">
<input type="radio" name="color-radio" checked>
<span class="acc-radio-dot"></span>
<span>High contrast radio</span>
</label>
</div>
</div>
<div class="demo-section">
<h2>ARIA Attributes & Semantics</h2>
<div class="code-example">
/* ARIA Implementation */<br>
aria-checked for state<br>
aria-label for additional context<br>
role attributes when needed
</div>
<div class="aria-example">
<strong>ARIA Best Practices:</strong>
<ul style="margin-top: 0.5rem; padding-left: 1.5rem;">
<li>Use native HTML elements when possible</li>
<li>Add aria-label for icon-only buttons</li>
<li>Use aria-describedby for additional information</li>
<li>Maintain proper heading structure</li>
</ul>
</div>
<div class="input-group">
<div class="input-title">ARIA Enhanced Inputs</div>
<!-- Checkbox with ARIA -->
<label class="acc-checkbox">
<input type="checkbox" aria-checked="false" aria-label="Accept terms and conditions">
<span class="acc-checkmark"></span>
<span>I accept the terms</span>
</label>
<!-- Radio with ARIA -->
<label class="acc-radio">
<input type="radio" name="aria-radio" aria-checked="true" aria-label="Standard shipping option">
<span class="acc-radio-dot"></span>
<span>Standard Shipping</span>
</label>
<!-- Disabled with ARIA -->
<label class="acc-checkbox disabled">
<input type="checkbox" disabled aria-disabled="true">
<span class="acc-checkmark"></span>
<span>Disabled option</span>
</label>
</div>
</div>
<div class="demo-section">
<h2>Screen Reader Compatibility</h2>
<div class="code-example">
/* Screen Reader Support */<br>
Proper label association<br>
Hidden visual elements<br>
Descriptive text alternatives
</div>
<div class="accessibility-note">
✅ <strong>Good:</strong> Screen readers can properly announce custom inputs when they're implemented with semantic HTML and ARIA.
</div>
<div class="input-group">
<div class="input-title">Screen Reader Friendly</div>
<fieldset style="border: 2px solid #e5e7eb; border-radius: 8px; padding: 1rem;">
<legend style="font-weight: 600; padding: 0 0.5rem;">
Shipping Method
<span class="sr-only">: Choose one option</span>
</legend>
<label class="acc-radio">
<input type="radio" name="shipping" checked>
<span class="acc-radio-dot"></span>
<span>
Standard Shipping
<span style="display: block; font-size: 0.875rem; color: #6b7280;">
3-5 business days
</span>
</span>
</label>
<label class="acc-radio">
<input type="radio" name="shipping">
<span class="acc-radio-dot"></span>
<span>
Express Shipping
<span style="display: block; font-size: 0.875rem; color: #6b7280;">
1-2 business days
</span>
</span>
</label>
</fieldset>
</div>
</div>
<div class="demo-section">
<h2>Error States & Validation</h2>
<div class="code-example">
/* Accessible Error Handling */<br>
aria-invalid for error states<br>
aria-describedby for error messages<br>
Clear visual error indicators
</div>
<div class="input-group">
<div class="input-title">Form Validation Example</div>
<div style="margin-bottom: 1rem; padding: 1rem; background: #fef2f2; border: 1px solid #fecaca; border-radius: 8px;">
<strong style="color: #dc2626;">Required:</strong> Please accept the terms to continue.
</div>
<label class="acc-checkbox" style="border-color: #dc2626;">
<input type="checkbox" aria-invalid="true" aria-describedby="terms-error">
<span class="acc-checkmark" style="border-color: #dc2626;"></span>
<span>I agree to the terms and conditions</span>
</label>
<div id="terms-error" style="color: #dc2626; font-size: 0.875rem; margin-top: 0.5rem;">
You must accept the terms to proceed.
</div>
</div>
</div>
</div>
<script>
// Accessibility enhancements
const accInputs = document.querySelectorAll('.acc-checkbox input, .acc-radio input');
// Update ARIA attributes dynamically
accInputs.forEach(input => {
// Set initial ARIA states
if (input.type === 'checkbox') {
input.setAttribute('aria-checked', input.checked);
} else if (input.type === 'radio') {
input.setAttribute('aria-checked', input.checked);
}
// Update ARIA on change
input.addEventListener('change', function() {
if (this.type === 'checkbox') {
this.setAttribute('aria-checked', this.checked);
} else if (this.type === 'radio') {
// Update all radios in group
const groupName = this.name;
document.querySelectorAll(`input[name="${groupName}"]`).forEach(radio => {
radio.setAttribute('aria-checked', radio.checked);
});
}
// Announce changes to screen readers
const label = this.parentElement.textContent.trim();
const state = this.checked ? 'checked' : 'unchecked';
console.log(`${label} ${state}`); // In real implementation, use live region
});
});
// Focus management demo
const focusableInputs = document.querySelectorAll('.acc-checkbox, .acc-radio');
focusableInputs.forEach(input => {
input.addEventListener('focus', function() {
console.log('Input focused:', this.textContent.trim());
});
});
// Error state simulation
const errorCheckbox = document.querySelector('[aria-invalid="true"]');
setTimeout(() => {
errorCheckbox.checked = true;
errorCheckbox.setAttribute('aria-invalid', 'false');
errorCheckbox.parentElement.style.borderColor = 'transparent';
document.getElementById('terms-error').style.display = 'none';
document.querySelector('[style*="background: #fef2f2"]').style.display = 'none';
}, 5000);
</script>
</body>
</html>Best Practices & Common Pitfalls
✅ Do This
- Use semantic
<label>elements - Provide clear focus indicators
- Ensure sufficient color contrast
- Use appropriate sizes (44px+ for mobile)
- Test with screen readers
- Maintain native functionality
❌ Avoid This
- Don't remove native input completely
- Avoid low contrast colors
- Don't forget hover and focus states
- Avoid tiny touch targets
- Don't break keyboard navigation
- Avoid complex animations that cause motion sickness
🚀 Performance Tips
CSS Transitions
Use transform and opacity for better performance
Reduced Motion
Respect prefers-reduced-motion preference
Efficient Selectors
Use specific CSS selectors for better performance
CSS Variables
Use custom properties for theming and maintenance
Ready to Create Amazing Custom Inputs? ☑️
Experiment with our comprehensive custom input examples and create beautiful, accessible forms that enhance your user experience.