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
:checked
pseudo-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.