Back

Creating a Modern Toggle Switch Button

Learn how to build a clean, animated toggle switch that can be used for settings, options, and binary choices in your interface.

HTML

The HTML structure for our toggle switch combines a checkbox input with label elements for better accessibility and user interaction.

        <div class="toggle-container">
          <label class="toggle-switch">
            <input type="checkbox">
            <span class="slider"></span>
            <span class="toggle-label">Toggle me</span>
          </label>
        </div>
      
This structure offers several benefits: - The checkbox remains functional but is visually hidden - Wrapping everything in a label allows users to toggle by clicking the text - Screen readers can properly announce the toggle state

CSS

First, we set up the container to center our toggle switch:

        .toggle-container {
          display: flex;
          justify-content: center;
          align-items: center;
          padding: 16px;
        }
      
Next, we define the toggle switch with CSS variables for customization:

        .toggle-switch {
          --toggle-width: 60px;
          --toggle-height: 32px;
          --toggle-padding: 4px;
          --toggle-animation-duration: 0.3s;
          --toggle-shadow-color: rgba(0, 0, 0, 0.2);
          --toggle-off-color: #ccc;
          --toggle-on-color: #4ade80;
          --toggle-hover-off-color: #9ca3af;
          --toggle-hover-on-color: #22c55e;
          
          position: relative;
          display: inline-flex;
          align-items: center;
          cursor: pointer;
          user-select: none;
        }
        
        .toggle-label {
          margin-left: 12px;
          font-family: system-ui, -apple-system, sans-serif;
          font-size: 16px;
          font-weight: 500;
          color: #374151;
        }
      
We hide the actual checkbox input while keeping it accessible to screen readers and keyboard navigation:

        .toggle-switch input {
          opacity: 0;
          width: 0;
          height: 0;
          position: absolute;
        }
      
Next, we style the slider track and the moving circle:

        .slider {
          position: relative;
          display: inline-block;
          width: var(--toggle-width);
          height: var(--toggle-height);
          background-color: var(--toggle-off-color);
          border-radius: calc(var(--toggle-height) / 2);
          transition: background-color var(--toggle-animation-duration) ease;
        }
        
        .slider::before {
          content: '';
          position: absolute;
          left: var(--toggle-padding);
          bottom: var(--toggle-padding);
          width: calc(var(--toggle-height) - 2 * var(--toggle-padding));
          height: calc(var(--toggle-height) - 2 * var(--toggle-padding));
          background-color: white;
          border-radius: 50%;
          box-shadow: 0 2px 4px var(--toggle-shadow-color);
          transition: transform var(--toggle-animation-duration) ease;
        }
      
We add hover states to improve user feedback:

        .toggle-switch:hover .slider {
          background-color: var(--toggle-hover-off-color);
        }
      
Now we handle the checked state, which moves the circle and changes the background color:

        input:checked + .slider {
          background-color: var(--toggle-on-color);
        }
        
        .toggle-switch:hover input:checked + .slider {
          background-color: var(--toggle-hover-on-color);
        }
        
        input:checked + .slider::before {
          transform: translateX(calc(var(--toggle-width) - var(--toggle-height)));
        }
      
The transform property moves the circle to the right when checked, creating the toggle effect. Finally, we add focus states for keyboard navigation and accessibility:

        input:focus + .slider {
          box-shadow: 0 0 1px var(--toggle-on-color);
        }
        
        /* Accessibility */
        input:focus-visible + .slider {
          outline: 2px solid var(--toggle-on-color);
          outline-offset: 2px;
        }
      
For added flexibility, we define size and color variants:

        /* Optional: Different sizes */
        .toggle-switch.small {
          --toggle-width: 48px;
          --toggle-height: 24px;
        }
        
        .toggle-switch.large {
          --toggle-width: 72px;
          --toggle-height: 40px;
        }
        
        /* Optional: Different state styles */
        .toggle-switch.success { --toggle-on-color: #4ade80; --toggle-hover-on-color: #22c55e; }
        .toggle-switch.danger { --toggle-on-color: #ef4444; --toggle-hover-on-color: #dc2626; }
        .toggle-switch.warning { --toggle-on-color: #f59e0b; --toggle-hover-on-color: #d97706; }
        .toggle-switch.info { --toggle-on-color: #3b82f6; --toggle-hover-on-color: #2563eb; }
      
These classes allow you to quickly create toggles in different sizes and colors for different contexts. This toggle switch offers several advantages: - Intuitive interaction: Users instantly recognize toggle switches for binary options. - Space efficiency: Toggles take up less space than radio buttons or dropdowns for yes/no choices. - Immediate feedback: The animation and color change provide clear visual confirmation of state changes. - Accessibility: Built with standard form controls that work with keyboard navigation and screen readers. - Customizable: Easy to adjust sizes, colors, and animations through CSS variables. This component is perfect for settings pages, preference menus, feature toggles, and any interface where users need to make binary choices.

Whole code

<div class="toggle-container">
  <label class="toggle-switch">
    <input type="checkbox">
    <span class="slider"></span>
    <span class="toggle-label">Toggle me</span>
  </label>
</div>

<style>
.toggle-container {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 16px;
}

.toggle-switch {
  --toggle-width: 60px;
  --toggle-height: 32px;
  --toggle-padding: 4px;
  --toggle-animation-duration: 0.3s;
  --toggle-shadow-color: rgba(0, 0, 0, 0.2);
  --toggle-off-color: #ccc;
  --toggle-on-color: #4ade80;
  --toggle-hover-off-color: #9ca3af;
  --toggle-hover-on-color: #22c55e;
  
  position: relative;
  display: inline-flex;
  align-items: center;
  cursor: pointer;
  user-select: none;
}

.toggle-label {
  margin-left: 12px;
  font-family: system-ui, -apple-system, sans-serif;
  font-size: 16px;
  font-weight: 500;
  color: #374151;
}

.toggle-switch input {
  opacity: 0;
  width: 0;
  height: 0;
  position: absolute;
}

.slider {
  position: relative;
  display: inline-block;
  width: var(--toggle-width);
  height: var(--toggle-height);
  background-color: var(--toggle-off-color);
  border-radius: calc(var(--toggle-height) / 2);
  transition: background-color var(--toggle-animation-duration) ease;
}

.slider::before {
  content: '';
  position: absolute;
  left: var(--toggle-padding);
  bottom: var(--toggle-padding);
  width: calc(var(--toggle-height) - 2 * var(--toggle-padding));
  height: calc(var(--toggle-height) - 2 * var(--toggle-padding));
  background-color: white;
  border-radius: 50%;
  box-shadow: 0 2px 4px var(--toggle-shadow-color);
  transition: transform var(--toggle-animation-duration) ease;
}

.toggle-switch:hover .slider {
  background-color: var(--toggle-hover-off-color);
}

input:checked + .slider {
  background-color: var(--toggle-on-color);
}

.toggle-switch:hover input:checked + .slider {
  background-color: var(--toggle-hover-on-color);
}

input:checked + .slider::before {
  transform: translateX(calc(var(--toggle-width) - var(--toggle-height)));
}

input:focus + .slider {
  box-shadow: 0 0 1px var(--toggle-on-color);
}

/* Accessibility */
input:focus-visible + .slider {
  outline: 2px solid var(--toggle-on-color);
  outline-offset: 2px;
}

/* Optional: Different sizes */
.toggle-switch.small {
  --toggle-width: 48px;
  --toggle-height: 24px;
}

.toggle-switch.large {
  --toggle-width: 72px;
  --toggle-height: 40px;
}

/* Optional: Different state styles */
.toggle-switch.success { --toggle-on-color: #4ade80; --toggle-hover-on-color: #22c55e; }
.toggle-switch.danger { --toggle-on-color: #ef4444; --toggle-hover-on-color: #dc2626; }
.toggle-switch.warning { --toggle-on-color: #f59e0b; --toggle-hover-on-color: #d97706; }
.toggle-switch.info { --toggle-on-color: #3b82f6; --toggle-hover-on-color: #2563eb; }
</style>
      
Thank you for reading this article.

Comments

More toggle-buttons

Similar

See also