Password Reveal
A password field with an eye toggle that shows the value while it is pressed. pressedchange flips the input's type between password and text, and the icon pair swaps through :state(--pressed).
The accessible name stays "Show password" in both states. The pressed state itself tells assistive technology whether the password is visible, so the label must not flip with it.
Code
The following example assumes that you have imported the component and set up the theme.
<div class="password-field">21 collapsed lines
<label for="password-input">Password</label>
<div class="field"> <input id="password-input" type="password" autocomplete="off" spellcheck="false" value="correct-horse-battery" />
<sv-toggle class="reveal" aria-label="Show password" title="Show password"> <!-- Eye --> <svg class="icon eye" aria-hidden="true" viewBox="0 -960 960 960" xmlns="http://www.w3.org/2000/svg"> <path d="M480-320q75 0 127.5-52.5T660-500q0-75-52.5-127.5T480-680q-75 0-127.5 52.5T300-500q0 75 52.5 127.5T480-320Zm0-72q-45 0-76.5-31.5T372-500q0-45 31.5-76.5T480-608q45 0 76.5 31.5T588-500q0 45-31.5 76.5T480-392Zm0 192q-146 0-266-81.5T40-500q54-137 174-218.5T480-800q146 0 266 81.5T920-500q-54 137-174 218.5T480-200Zm0-300Zm0 220q113 0 207.5-59.5T832-500q-50-101-144.5-160.5T480-720q-113 0-207.5 59.5T128-500q50 101 144.5 160.5T480-280Z" ></path> </svg>
<!-- Crossed eye --> <svg class="icon eye-off" aria-hidden="true" viewBox="0 -960 960 960" xmlns="http://www.w3.org/2000/svg"> <path d="m644-428-58-58q9-47-27-88t-93-32l-58-58q17-8 34.5-12t37.5-4q75 0 127.5 52.5T660-500q0 20-4 37.5T644-428Zm128 126-58-56q38-29 67.5-63.5T832-500q-50-101-143.5-160.5T480-720q-29 0-57 4t-55 12l-62-62q41-17 84-25.5t90-8.5q151 0 269 83.5T920-500q-23 59-60.5 109.5T772-302Zm20 246L624-222q-35 11-70.5 16.5T480-200q-151 0-269-83.5T40-500q21-53 53-98.5t73-81.5L56-792l56-56 736 736-56 56ZM222-624q-29 26-53 57t-41 67q50 101 143.5 160.5T480-280q20 0 39-2.5t39-5.5l-36-38q-11 3-21 4.5t-21 1.5q-75 0-127.5-52.5T300-500q0-11 1.5-21t4.5-21l-84-82Zm319 93Zm-151 75Z" ></path> </svg> </sv-toggle> </div></div>
<script type="application/x-typescript" module>6 collapsed lines
const input = document.querySelector<HTMLInputElement>("#password-input")!; const toggle = document.querySelector<Toggle>(".reveal")!;
toggle.addEventListener("pressedchange", () => { input.type = toggle.pressed ? "text" : "password"; });</script>
<style>67 collapsed lines
.password-field { display: grid; gap: 0.4em; max-inline-size: 20rem; margin-inline: auto;
label { font-weight: 600; }
.field { display: flex; align-items: center; background-color: var(--sv-gray-7); border: solid var(--sv-bdr-sz-sm) var(--sv-gray-5); border-radius: var(--sv-bdr-rad-md);
&:focus-within { border-color: var(--sv-accent); }
input { flex: 1; min-inline-size: 0; padding: 0.6em 0.8em; font: inherit; color: inherit; outline: none; background: none; border: none; } }
.reveal { display: inline-grid; place-items: center; padding: 0.4em; margin-inline-end: 0.3em; color: var(--sv-gray-2); background-color: transparent; border: none;
.icon { grid-area: 1 / 1; inline-size: 1.2em; block-size: 1.2em; fill: currentcolor; }
.icon.eye-off { visibility: hidden; }
&:state(--pressed) { color: var(--sv-gray-1); background-color: transparent;
.icon.eye { visibility: hidden; }
.icon.eye-off { visibility: visible; } } } }</style>