Accessible toggle switch.
With different styles using icons
A Pen by IpsumLorem16 on CodePen.
Accessible toggle switch.
With different styles using icons
A Pen by IpsumLorem16 on CodePen.
<!-- Bigger --> | |
<div class="toggle-container"> | |
<label for="biggerSwitch" class="toggle-switch"> | |
Bigger | |
</label> | |
<button role="switch" aria-checked="true" id="biggerSwitch" class="toggle-switch tog-big"> | |
<span aria-hidden="true">✔</span> | |
<span class="knob"></span> | |
<span aria-hidden="true">✖</span> | |
</button> | |
</div> | |
<!-- Knob Icon & bigger --> | |
<div class="toggle-container"> | |
<label for="knobIcon" class="toggle-switch"> | |
Knob Icon | |
</label> | |
<button role="switch" aria-checked="false" id="knobIcon" class="toggle-switch tog-big knob-icon" > | |
<span aria-hidden="true"></span> | |
<span class="knob" data-on="✔" data-off="✖"></span> | |
<span aria-hidden="true"></span> | |
</button> | |
</div> | |
<!-- Original size, one Icon --> | |
<div class="toggle-container"> | |
<label for="oneIcon" class="toggle-switch"> | |
One Icon | |
</label> | |
<button role="switch" aria-checked="false" id="oneIcon" class="toggle-switch no-off"> | |
<span aria-hidden="true">✔</span> | |
<span class="knob"></span> | |
<span aria-hidden="true"></span> | |
</button> | |
</div> | |
<!-- Alt colors, Knob icon, big --> | |
<div class="toggle-container"> | |
<label for="altColor" class="toggle-switch"> | |
Alt Colors | |
</label> | |
<button role="switch" aria-checked="true" id="altColor" class="toggle-switch tog-big knob-icon alt-col" > | |
<span aria-hidden="true"></span> | |
<span class="knob" data-on="✔" data-off="✖"></span> | |
<span aria-hidden="true"></span> | |
</button> | |
</div> | |
<!-- Night day toggle --> | |
<div class="toggle-container"> | |
<label for="nightDay" class="toggle-switch"> | |
Night day | |
</label> | |
<button role="switch" aria-checked="true" id="nightDay" class="toggle-switch tog-big night-day" > | |
<span aria-hidden="true"></span> | |
<span class="knob"></span> | |
<span aria-hidden="true"> | |
<span class="stars-container"> | |
<span class="star"></span> | |
<span class="star"></span> | |
<span class="star"></span> | |
<span class="star"></span> | |
<span class="star"></span> | |
<span class="star"></span> | |
<span class="star"></span> | |
</span> | |
</span> | |
</button> | |
</div> |
document.querySelectorAll(".toggle-switch[role='switch']").forEach(switchEl => { | |
switchEl.addEventListener("click", handleToggleClick, false); | |
//prevent focus on switch when clicking on it | |
switchEl.addEventListener("mousedown", event => { | |
event.preventDefault(); | |
}); | |
}); | |
function handleToggleClick(event) { | |
let switchEl = event.target; | |
//if not disabled toggle attribute | |
if (!switchEl.hasAttribute("aria-readonly")) { | |
let currState = switchEl.getAttribute("aria-checked"); | |
let newState = currState === "true" ? false : true; | |
switchEl.setAttribute("aria-checked", newState); | |
} | |
} | |
//prevent focus to switch, on clicking label | |
document.querySelectorAll("label.toggle-switch").forEach(labelEl => { | |
labelEl.addEventListener("click", event => { | |
event.preventDefault(); //prevent focus | |
event.target.control.click(); //activate switch | |
}); | |
}); |
body { | |
background: #1d1d1d; | |
} | |
.toggle-container { | |
display: inline-block; | |
padding: 20px; | |
background-color: #ffffff1f; | |
margin: 4px; | |
} | |
label.toggle-switch { | |
margin-bottom: 4px; | |
margin-right: 4px; | |
font-family: Arial, sans-serif; | |
color: white; | |
user-select: none; | |
} | |
button.toggle-switch { | |
-webkit-tap-highlight-color: transparent; | |
position: relative; | |
width: 50px; | |
height: 26px; | |
padding: 1px 6px; | |
background-color: #d8d9db; | |
outline: none; | |
border: none; | |
color: white; | |
border-radius: 20px; | |
line-height: 20px; | |
cursor: pointer; | |
transition: all 0.3s; | |
&:focus { | |
box-shadow: 0px 0px 0px 3px #fff; | |
} | |
&::-moz-focus-inner { | |
border: 0; | |
outline: 0; | |
padding: 0; | |
} | |
/* on */ | |
&[aria-checked="true"] { | |
background-color: #4bd865; | |
:last-child { | |
opacity: 0; | |
transition: opacity 0.2s 0.1s; | |
} | |
} | |
/* off */ | |
&[aria-checked="false"] { | |
background-color: #ff5050; | |
:first-child { | |
opacity: 0; | |
transition: opacity 0.2s 0.1s; | |
} | |
} | |
/* disabled */ | |
&[aria-readonly="true"] { | |
cursor: not-allowed; | |
opacity: 0.8; | |
filter: grayscale(50%); | |
} | |
span { | |
pointer-events: none; | |
} | |
} | |
/* alt styles */ | |
button.toggle-switch { | |
/* Bigger */ | |
&.tog-big { | |
width: 80px; | |
height: 36px; | |
font-size: 18px; | |
:first-child { | |
margin-right: 20px; | |
} | |
.knob { | |
width: 30px; | |
height: 30px; | |
} | |
&[aria-checked="true"] .knob { | |
transform: translateX(44px); | |
} | |
} | |
/* Knob Icon */ | |
&.knob-icon { | |
& .knob:after { | |
line-height: 30px; | |
font-size: 14px; | |
} | |
&[aria-checked="true"] .knob:after { | |
content: attr(data-on); | |
color: #4bd865; | |
} | |
&[aria-checked="false"] .knob:after { | |
content: attr(data-off); | |
color: #ff5050; | |
} | |
} | |
/* One Icon */ | |
&.no-off { | |
:first-child { | |
padding-right: 17px; | |
} | |
&[aria-checked="false"] { | |
background-color: #d8d9db; | |
} | |
} | |
/* Alt colors */ | |
&.alt-col { | |
&[aria-checked="true"] { | |
background-color: #ebf7fc; | |
.knob { | |
background-color: #03a9f4; | |
&:after { | |
color: white; | |
} | |
} | |
&:focus { | |
box-shadow: 0px 0px 0px 3px #8a8a8a; | |
} | |
} | |
&[aria-checked="false"] { | |
background-color: #fcebeb; | |
.knob { | |
background-color: #f44336; | |
&:after { | |
color: white; | |
} | |
} | |
&:focus { | |
box-shadow: 0px 0px 0px 3px #b691a0; | |
} | |
} | |
} | |
/* Night day */ | |
&.night-day { | |
margin-left:3px; | |
.knob { | |
box-sizing: border-box; | |
} | |
&[aria-checked="true"] { | |
background-color: #bfe6f6; | |
box-shadow: 0px 0px 0px 3px #81c1d6; | |
&:focus { | |
box-shadow: 0px 0px 0px 3px #81c1d6, 0px 0px 0px 6px white; | |
} | |
.knob { | |
background-color: #f5ec27; | |
border: 3px solid #e4c53e; | |
} | |
} | |
&[aria-checked="false"] { | |
background-color: #484848; | |
box-shadow: 0px 0px 0px 3px #1e1e1e; | |
&:focus { | |
box-shadow: 0px 0px 0px 3px #1e1e1e, 0px 0px 0px 6px white; | |
} | |
.knob { | |
background-color:#fffdf1; | |
border: 3px solid #e0e3c3; | |
} | |
.stars-container { | |
width:100%; | |
height:100%; | |
position: absolute; | |
top:0; | |
right:0; | |
border-radius: 20px; | |
opacity: 1; | |
margin-right: 0; | |
.star { | |
width:3px; | |
height:3px; | |
position: absolute; | |
background-color:white; | |
border-radius: 50%; | |
opacity:1; | |
&:nth-of-type(1) { | |
top: 15%; | |
left: 45%; | |
} | |
&:nth-of-type(2) { | |
top: 71%; | |
left: 50%; | |
width: 4px; | |
height: 4px; | |
} | |
&:nth-of-type(3) { | |
top:34%; | |
left:59%; | |
width:2px; | |
height:2px; | |
} | |
&:nth-of-type(4) { | |
top:55%; | |
left:65%; | |
width:2px; | |
height:2px; | |
} | |
&:nth-of-type(5) { | |
top:10%; | |
left: 75%; | |
} | |
&:nth-of-type(6) { | |
top:41%; | |
left:85%; | |
width:4px; | |
height:4px; | |
} | |
&:nth-of-type(7) { | |
top: 60%; | |
left:80%; | |
} | |
} | |
} | |
} | |
} | |
} | |
.knob { | |
button.toggle-switch & { | |
position: absolute; | |
width: 20px; | |
height: 20px; | |
border-radius: 50%; | |
background-color: white; | |
top: 3px; | |
left: 3px; | |
transition: all 0.3s; | |
} | |
button.toggle-switch[aria-checked="true"] & { | |
transform: translateX(24px); | |
} | |
} |