<p>This is a toggle that overrides a native HTML checkbox input element.</p>

<div class="toggle-switch" tabindex="0">
  <input type="checkbox" name="my_checkbox" value="yes" id="checkbox-id" />
  <label for="checkbox-id">
    <div class="area" aria-hidden="true">
      <div class="background">
        <div class="handle"></div>
      </div>
    </div>
    A text label
  </label>
</div>

<p>The toggle is hidden from accessibility tools, such as screen readers, which will use the native HTML checkbox. Keyboard users can tab to the element and toggle it with the <kbd>SPACE</kbd> key.</p>
.toggle-switch {
  --width: 30px;
  --height: 20px;
  --padding: 2px;
  --handle-size: calc(var(--height) - var(--padding) * 2);
  
  display: inline-block;
  outline-width: 0;
}

.toggle-switch > input {
  position: absolute;
  clip: rect(1px, 1px, 1px, 1px);
  clip-path: inset(50%);
  height: 1px;
  width: 1px;
  margin: -1px;
  overflow: hidden;
}

label {
  display: inline-grid;
  grid-template-columns: auto auto;
  column-gap: 10px;
}

.area {
  padding: 4px;
  margin: -4px;
}

.toggle-switch :active {
  outline-width: 0;
}

.background,
.handle {
  transition: all 0.1s ease;
}

.background {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  width: var(--width);
  height: var(--height);
  border-radius: var(--height);
  padding: 0 var(--padding);
  vertical-align: text-bottom;
  user-select: none;
  background-color: darkgray;
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.25);
  overflow: hidden;
  transition: background-color .15s ease;
}

.toggle-switch:focus .area {
  outline: 1px dotted gray;  
}

.toggle-switch:active .area {
  outline-width: 0;
}

.toggle-switch:focus .background,
.area:hover .background {
  background-color: gray;
}

.handle {
  width: var(--handle-size);
  height: var(--handle-size);
  background-color: white;
  border-radius: 50%;
  box-shadow:
    0 2px 4px rgba(0, 0, 0, 0.5),
    inset 0 2px 4px rgba(0, 0, 0, 0.15);
}

.handle:hover {
  background-color: white;
}

input:checked + label .area .background {
  background-color: lightgreen;
}

input:checked + label .area .handle {
  background-color: white;
  transform: translateX(calc(var(--width) - var(--handle-size)));
}

/**
 * Styles for Codepen.
 */
body {
  font-family: sans-serif;
  color: #3f3f3f;
  max-width: 480px;
  margin: 20px auto;
  padding: 0 20px;
  line-height: 1.35;
}

@media (min-width: 640px) {
  body {
    margin-top: 40px;
  }
}
View Compiled
const $ = selector => [...document.querySelectorAll(selector)];

const onKeyPress = ( { key, target }) => {
  if (key !== " ") return;
  const element = target.querySelector('input');
  element.checked = !element.checked;
};

$(".toggle-switch").forEach(element => {
  element.addEventListener("keypress", onKeyPress);
});
        
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.