Repository Public
1<!--2 ============================================================3 SVGarden — https://www.svgarden.dev4 Author : Simon-Pierre Boucher5 Contact: contact@spboucher.ai6 File : snippets/interactive/password-eye-blink.html7 Desc : Show/hide password field whose eye icon blinks when toggled8 ============================================================9-->10<!--svgarden11title: Password eye blink12slug: password-eye-blink13category: interactive14tags: [interactive, password, toggle, checkbox, form]15difficulty: intermediate16techniques: [":checked", sibling-combinator, scaleY-blink, crossfade, ":focus-visible"]17how_it_works: >18 A hidden checkbox placed *before* the field holds the shown/hidden state, so19 everything after it is reachable with the general sibling combinator — the20 CSS-only pattern for "one control drives many elements". The field stacks21 two spans (dots and plain text) and :checked crossfades between them, while22 the slash over the eye fades away. The blink is the fun part: the eye group23 runs a scaleY squeeze keyframe that only exists under the :checked selector,24 and because the selector starts matching at the moment you toggle, the25 animation restarts precisely then — CSS animations as event handlers.26customizable:27 - { var: "--sg-color", label: "Accent", type: color, default: "#7F77DD" }28 - { var: "--sg-size", label: "Width", type: range, min: 180, max: 380, default: 250, unit: px }29 - { var: "--sg-duration", label: "Speed", type: range, min: 0.15, max: 0.9, step: 0.05, default: 0.4, unit: s }30created: 2026-08-1031-->32<div class="sg-password-eye-blink" style="--sg-color:#7F77DD; --sg-size:250px; --sg-duration:0.4s;">33 <input type="checkbox" id="sg-password-eye-blink-cb" class="sg-password-eye-blink-cb" />34 <div class="sg-password-eye-blink-field">35 <span class="sg-password-eye-blink-text">36 <span class="sg-password-eye-blink-dots" aria-hidden="true">••••••••</span>37 <span class="sg-password-eye-blink-plain">hunter2!</span>38 </span>39 <label for="sg-password-eye-blink-cb" class="sg-password-eye-blink-eye" aria-label="Show password">40 <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">41 <g class="sg-password-eye-blink-ball">42 <path d="M2.5 12 C 6.5 5.5, 17.5 5.5, 21.5 12 C 17.5 18.5, 6.5 18.5, 2.5 12 Z" />43 <circle cx="12" cy="12" r="3.2" />44 </g>45 <line class="sg-password-eye-blink-slash" x1="4.5" y1="19.5" x2="19.5" y2="4.5" />46 </svg>47 </label>48 </div>49</div>50<style>51 .sg-password-eye-blink {52 width: var(--sg-size);53 font-family: inherit;54 }55 .sg-password-eye-blink-cb {56 position: absolute;57 opacity: 0;58 width: 1px;59 height: 1px;60 }61 .sg-password-eye-blink-field {62 display: flex;63 align-items: center;64 gap: 0.6rem;65 border: 1px solid rgba(128, 128, 128, 0.45);66 border-radius: 10px;67 padding: 0.6rem 0.75rem;68 }69 .sg-password-eye-blink-text {70 position: relative;71 flex: 1;72 font-family: ui-monospace, Menlo, monospace;73 font-size: 0.95rem;74 letter-spacing: 0.06em;75 min-height: 1.3em;76 }77 .sg-password-eye-blink-dots,78 .sg-password-eye-blink-plain {79 position: absolute;80 left: 0;81 top: 50%;82 translate: 0 -50%;83 transition: opacity var(--sg-duration) ease, translate var(--sg-duration) ease;84 }85 .sg-password-eye-blink-plain {86 opacity: 0;87 translate: 0 calc(-50% + 5px);88 }89 .sg-password-eye-blink-eye {90 width: 1.5em;91 cursor: pointer;92 display: block;93 flex: none;94 }95 .sg-password-eye-blink-eye svg {96 display: block;97 width: 100%;98 overflow: visible;99 }100 .sg-password-eye-blink-ball {101 transform-box: fill-box;102 transform-origin: center;103 }104 .sg-password-eye-blink-ball path {105 fill: none;106 stroke: rgba(128, 128, 128, 0.8);107 stroke-width: 1.8;108 }109 .sg-password-eye-blink-ball circle {110 fill: var(--sg-color);111 }112 .sg-password-eye-blink-slash {113 stroke: rgba(128, 128, 128, 0.8);114 stroke-width: 1.8;115 stroke-linecap: round;116 transition: opacity var(--sg-duration) ease;117 }118 .sg-password-eye-blink-cb:checked ~ .sg-password-eye-blink-field .sg-password-eye-blink-dots {119 opacity: 0;120 translate: 0 calc(-50% - 5px);121 }122 .sg-password-eye-blink-cb:checked ~ .sg-password-eye-blink-field .sg-password-eye-blink-plain {123 opacity: 1;124 translate: 0 -50%;125 }126 .sg-password-eye-blink-cb:checked ~ .sg-password-eye-blink-field .sg-password-eye-blink-slash {127 opacity: 0;128 }129 .sg-password-eye-blink-cb:checked ~ .sg-password-eye-blink-field .sg-password-eye-blink-ball {130 animation: sg-password-eye-blink-wink calc(var(--sg-duration) * 1.4) ease;131 }132 .sg-password-eye-blink-cb:focus-visible ~ .sg-password-eye-blink-field {133 outline: 2px solid var(--sg-color);134 outline-offset: 2px;135 }136 @keyframes sg-password-eye-blink-wink {137 0%, 100% { transform: scaleY(1); }138 45% { transform: scaleY(0.08); }139 }140</style>141