Skip to main content

HOW TO CREATE SWITCH BUTTON

 

                            



                                                SWITCH BUTTON WITH HTML

<label for="switch-1" class="gui-switch"> Default <input type="checkbox" role="switch" id="switch-1"> </label> <label for="switch-2" class="gui-switch"> Indeterminate <input type="checkbox" role="switch" id="switch-2"> <script>document.getElementById('switch-2').indeterminate = true</script> </label> <label for="switch-3" class="gui-switch"> Disabled <input type="checkbox" role="switch" id="switch-3" disabled> </label> <label for="switch-4" class="gui-switch"> Disabled (checked) <input type="checkbox" role="switch" id="switch-4" disabled checked> </label> <label for="switch-vertical" class="gui-switch -vertical"> Vertical <input type="checkbox" role="switch" id="switch-vertical"> </label>


SWITCH BUTTON WITH JS


const elements = document.querySelectorAll('.gui-switch') const switches = new WeakMap() const state = { activethumb: null, recentlyDragged: false, } const getStyle = (element, prop) => parseInt( window.getComputedStyle(element) .getPropertyValue(prop)) const getPseudoStyle = (element, prop) => parseInt( window.getComputedStyle(element, ':before') .getPropertyValue(prop)) const dragInit = event => { if (event.target.disabled) return state.activethumb = event.target state.activethumb.addEventListener('pointermove', dragging) state.activethumb.style.setProperty('--thumb-transition-duration', '0s') } const dragging = event => { if (!state.activethumb) return let {thumbsize, bounds, padding} = switches.get(state.activethumb.parentElement) let directionality = getStyle(state.activethumb, '--isLTR') let track = (directionality === -1) ? (state.activethumb.clientWidth * -1) + thumbsize + padding : 0 let pos = Math.round(event.offsetX - thumbsize / 2) if (pos < bounds.lower) pos = 0 if (pos > bounds.upper) pos = bounds.upper state.activethumb.style.setProperty('--thumb-position', `${track + pos}px`) } const dragEnd = event => { if (!state.activethumb) return state.activethumb.checked = determineChecked() if (state.activethumb.indeterminate) state.activethumb.indeterminate = false state.activethumb.style.removeProperty('--thumb-transition-duration') state.activethumb.style.removeProperty('--thumb-position') state.activethumb.removeEventListener('pointermove', dragging) state.activethumb = null padRelease() } const padRelease = () => { state.recentlyDragged = true setTimeout(_ => { state.recentlyDragged = false }, 300) } const preventBubbles = event => { if (state.recentlyDragged) event.preventDefault() && event.stopPropagation() } const labelClick = event => { if ( state.recentlyDragged || !event.target.classList.contains('gui-switch') || event.target.querySelector('input').disabled ) return let checkbox = event.target.querySelector('input') checkbox.checked = !checkbox.checked event.preventDefault() } const determineChecked = () => { let {bounds} = switches.get(state.activethumb.parentElement) let curpos = Math.abs( parseInt( state.activethumb.style.getPropertyValue('--thumb-position'))) if (!curpos) { curpos = state.activethumb.checked ? bounds.lower : bounds.upper } return curpos >= bounds.middle } elements.forEach(guiswitch => { let checkbox = guiswitch.querySelector('input') let thumbsize = getPseudoStyle(checkbox, 'width') let padding = getStyle(checkbox, 'padding-left') + getStyle(checkbox, 'padding-right') checkbox.addEventListener('pointerdown', dragInit) checkbox.addEventListener('pointerup', dragEnd) checkbox.addEventListener('click', preventBubbles) guiswitch.addEventListener('click', labelClick) switches.set(guiswitch, { thumbsize, padding, bounds: { lower: 0, middle: (checkbox.clientWidth - padding) / 4, upper: checkbox.clientWidth - thumbsize - padding, }, }) }) window.addEventListener('pointerup', event => { if (!state.activethumb) return dragEnd(event) })


        SWITCH BUTTON WITH CSS


.gui-switch { --thumb-size: 2rem; --thumb: hsl(0 0% 100%); --thumb-highlight: hsl(0 0% 0% / 25%); --track-size: calc(var(--thumb-size) * 2); --track-padding: 2px; --track-inactive: hsl(80 0% 80%); --track-active: hsl(80 60% 45%); --thumb-color: var(--thumb); --thumb-color-highlight: var(--thumb-highlight); --track-color-inactive: var(--track-inactive); --track-color-active: var(--track-active); --isLTR: 1; display: flex; align-items: center; gap: 2ch; justify-content: space-between; cursor: pointer; user-select: none; -webkit-tap-highlight-color: transparent; @media (prefers-color-scheme: dark) { --thumb: hsl(0 0% 5%); --thumb-highlight: hsl(0 0% 100% / 25%); --track-inactive: hsl(80 0% 35%); --track-active: hsl(80 60% 60%); } &:dir(rtl) { --isLTR: -1; } &.-vertical { min-block-size: calc(var(--track-size) + calc(var(--track-padding) * 2)); & > input { transform: rotate(calc(90deg * var(--isLTR) * -1)); touch-action: pan-x; } } & > input { --thumb-position: 0%; --thumb-transition-duration: .25s; padding: var(--track-padding); background: var(--track-color-inactive); inline-size: var(--track-size); block-size: var(--thumb-size); border-radius: var(--track-size); appearance: none; pointer-events: none; touch-action: pan-y; border: none; outline-offset: 5px; box-sizing: content-box; flex-shrink: 0; display: grid; align-items: center; grid: [track] 1fr / [track] 1fr; transition: background-color .25s ease; &::before { --highlight-size: 0; content: ""; cursor: pointer; pointer-events: auto; grid-area: track; inline-size: var(--thumb-size); block-size: var(--thumb-size); background: var(--thumb-color); box-shadow: 0 0 0 var(--highlight-size) var(--thumb-color-highlight); border-radius: 50%; transform: translateX(var(--thumb-position)); @media (--motionOK) { & { transition: transform var(--thumb-transition-duration) ease, box-shadow .25s ease; }} } &:not(:disabled):hover::before { --highlight-size: .5rem; } &:checked { background: var(--track-color-active); --thumb-position: calc((var(--track-size) - 100%) * var(--isLTR)); } &:indeterminate { --thumb-position: calc( calc(calc(var(--track-size) / 2) - calc(var(--thumb-size) / 2)) * var(--isLTR) ); } &:disabled { cursor: not-allowed; --thumb-color: transparent; &::before { cursor: not-allowed; box-shadow: inset 0 0 0 2px hsl(0 0% 100% / 50%); @media (prefers-color-scheme: dark) { box-shadow: inset 0 0 0 2px hsl(0 0% 0% / 50%); } } } } }



Comments

Popular posts from this blog

HOW TO CREATE COPY BUTTON WITH HTML, CSS AND JS LANGUAGE

                                                                                                                                                      STRUCTURE WITH  <HTML> <! DOCTYPE html > < html lang = " en " > < head > < meta charset = " utf-8 " /> < meta name = " viewport " content = " width=device-width, initial-scale=1 " /> < link rel = " icon " href = " data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🎉</text></svg> " /> < title > How to copy images </ title > </ head > < body > < h1 > How to copy images </ h1 > < img src = " assets/fugu.svg " alt = " Fugu fish. " width = " 128 " height = " 128 " > < button type = &quo

Autoplay carousel WITH HTML LANGUAGE

  Autoplay carousel HTML  < div id = " carousel " > < div id = " slide-container " > < div class = " slide " data-slideIndex = " 0 " > < div class = " slide-banner " > Tour the Empire State Building! < a href = " " > Buy tickets now. </ a > </ div > < img width = " 1200 " height = " 600 " src = " ./newyork.jpg " > </ div > < div class = " slide " data-slideIndex = " 1 " > < div class = " slide-banner " > Ride the Shinkansen! < a href = " " > Buy tickets now. </ a > </ div > < img width = " 1200 " height = " 600 " src = " ./tokyo.jpg " > </ div > < div class = " slide " data-slideIndex = " 2 " > < div class = " slide-bann

How to periodically synchronize data in the background

       How to periodically synchronize data in the background                                                                                                                                                                                                                    HTML <! DOCTYPE html > < html lang = " en " > < head > < meta charset = " utf-8 " /> < meta name = " viewport " content = " width=device-width, initial-scale=1 " /> < link rel = " icon " href = " " /> < link rel = " manifest " href = " ./manifest.json " /> < title > How to periodically synchronize data in the background </ title > < link rel = " stylesheet " href = " /style.css " /> < script src = " /script.js " defer > </ script > </ head > < body >