A Pen by Chris Pennington on CodePen.
Created
April 26, 2023 16:44
-
-
Save danydin/7308b9abd66de6835213375b810a6f4e to your computer and use it in GitHub Desktop.
Elastic Toggle Switch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <div class="container"> | |
| <div class="custom-check-wrapper"> | |
| <input type="checkbox" id="setting1" role="switch"> | |
| <div class="custom-check"> | |
| <div class="custom-check-thumb"></div> | |
| </div> | |
| <label for="setting1">Enable Setting 1</label> | |
| </div> | |
| <div class="custom-check-wrapper"> | |
| <input type="checkbox" id="setting2" role="switch"> | |
| <div class="custom-check"> | |
| <div class="custom-check-thumb"></div> | |
| </div> | |
| <label for="setting2">Enable Setting 2</label> | |
| </div> | |
| </div> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| document.querySelectorAll('[role="switch"]').forEach((toggle) => { | |
| toggle.addEventListener("change", () => { | |
| const isChecked = toggle.checked; | |
| const thumb = toggle | |
| .closest(".custom-check-wrapper") | |
| .querySelector(".custom-check-thumb"); | |
| thumb.style.animation = isChecked | |
| ? "toggleOn 200ms cubic-bezier(0.4, 0, 0.6, 1) forwards" | |
| : "toggleOff 200ms cubic-bezier(0.4, 0, 0.6, 1) forwards"; | |
| }); | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| *, *::after, *::before { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| @media (prefers-reduced-motion: reduce) { | |
| *, | |
| *::before, | |
| *::after { | |
| animation-duration: 0.01ms !important; | |
| animation-iteration-count: 1 !important; | |
| transition-duration: 0.01ms !important; | |
| scroll-behavior: auto !important; | |
| } | |
| } | |
| :root { | |
| --hue: 260; | |
| --accent: var(--hue) 80% 40%; | |
| --muted: var(--hue) 20% 90%; | |
| --bkg: var(--hue) 30% 98%; | |
| --text: var(--hue) 80% 9%; | |
| --fs-400: 2.5rem; | |
| --toggleHeight: 1.5em; | |
| } | |
| body { | |
| background-color: hsl(var(--bkg)); | |
| color: hsl(var(--text)); | |
| font-size: var(--fs-400); | |
| font-family: 'Inter', sans-serif; | |
| display: grid; | |
| place-items: center; | |
| min-height: 100vh; | |
| } | |
| .container { | |
| display: grid; | |
| gap: var(--fs-400); | |
| } | |
| .custom-check-wrapper { | |
| display: flex; | |
| align-items: center; | |
| gap: .75em; | |
| position: relative; | |
| } | |
| [role="switch"]{ | |
| appearance: none; | |
| --webkit-appearance: none; | |
| position: absolute; | |
| inset: 0; | |
| cursor: pointer; | |
| } | |
| [role="switch"]:focus { | |
| outline: 2px solid transparent; | |
| } | |
| [role="switch"]:focus-visible + .custom-check { | |
| box-shadow: | |
| 0 0 0 .15em hsl(var(--bkg)), | |
| 0 0 0 .4em hsl(var(--accent)); | |
| } | |
| .custom-check { | |
| width: calc(var(--toggleHeight) * 2); | |
| height: var(--toggleHeight); | |
| background-color: hsl(var(--muted)); | |
| border-radius: 100vmax; | |
| position: relative; | |
| pointer-events: none; | |
| transition: | |
| background-color 400ms cubic-bezier(0.4, 0, 0.6, 1), | |
| box-shadow 80ms cubic-bezier(0.4, 0, 0.6, 1); | |
| } | |
| .custom-check-thumb { | |
| position: absolute; | |
| background-color: hsl(var(--bkg)); | |
| border-radius: 100vmax; | |
| height: calc(var(--toggleHeight) * .834); | |
| width: calc(var(--toggleHeight) * .834); | |
| top: calc(var(--toggleHeight) * .084); | |
| left: calc(var(--toggleHeight) * .084); | |
| } | |
| [role="switch"]:checked + .custom-check { | |
| background-color: hsl(var(--accent)); | |
| } | |
| @keyframes toggleOn { | |
| 0% { | |
| width: calc(var(--toggleHeight) * .834); | |
| } | |
| 40% { | |
| width: calc(var(--toggleHeight) * 1.4); | |
| } | |
| 100% { | |
| width: calc(var(--toggleHeight) * .834); | |
| transform: translateX(var(--toggleHeight)); | |
| } | |
| } | |
| @keyframes toggleOff { | |
| 0% { | |
| width: calc(var(--toggleHeight) * .834); | |
| transform: translateX(var(--toggleHeight)); | |
| } | |
| 60% { | |
| width: calc(var(--toggleHeight) * 1.4); | |
| } | |
| 100% { | |
| width: calc(var(--toggleHeight) * .834); | |
| transform: translateX(0); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment