Toggle Custom Content
The default slot accepts any content: stack icons or labels, then animate or swap them with the :state(--pressed) CSS state. Give icon-only toggle buttons a title and an aria-label.
Code
The following example assumes that you have imported the component and set up the theme.
<div class="toggle-content-container"> <!-- Animated icon --> <sv-toggle class="favorite-toggle" aria-label="Favorite" title="Favorite">9 collapsed lines
<svg class="icon outline" aria-hidden="true" viewBox="0 -960 960 960" xmlns="http://www.w3.org/2000/svg"> <path d="m354-287 126-76 126 77-33-144 111-96-146-13-58-136-58 135-146 13 111 97-33 143ZM233-120l65-281L80-590l288-25 112-265 112 265 288 25-218 189 65 281-247-149-247 149Zm247-350Z" ></path> </svg>
<svg class="icon filled" aria-hidden="true" viewBox="0 -960 960 960" xmlns="http://www.w3.org/2000/svg"> <path d="m233-120 65-281L80-590l288-25 112-265 112 265 288 25-218 189 65 281-247-149-247 149Z"></path> </svg> </sv-toggle>
<!-- Icon and label --> <sv-toggle class="mute-toggle">13 collapsed lines
<span class="icon-stack" aria-hidden="true"> <svg class="icon volume-on" viewBox="0 -960 960 960" xmlns="http://www.w3.org/2000/svg"> <path d="M560-131v-82q90-26 145-100t55-168q0-94-55-168T560-749v-82q124 28 202 125.5T840-481q0 127-78 224.5T560-131ZM120-360v-240h160l200-200v640L280-360H120Zm440 40v-322q47 22 73.5 66t26.5 96q0 51-26.5 94.5T560-320ZM400-606l-86 86H200v80h114l86 86v-252ZM300-480Z" ></path> </svg>
<svg class="icon volume-off" viewBox="0 -960 960 960" xmlns="http://www.w3.org/2000/svg"> <path d="M792-56 671-177q-25 16-53 27.5T560-131v-82q14-5 27.5-10t25.5-12L480-368v208L280-360H120v-240h128L56-792l56-56 736 736-56 56Zm-8-232-58-58q17-31 25.5-65t8.5-70q0-94-55-168T560-749v-82q124 28 202 125.5T840-481q0 53-14.5 102T784-288ZM650-422l-90-90v-130q47 22 73.5 66t26.5 96q0 15-2.5 29.5T650-422ZM480-592 376-696l104-104v208Zm-80 238v-94l-72-72H200v80h114l86 86Zm-36-130Z" ></path> </svg> </span> Mute </sv-toggle>
<!-- Content swap --> <sv-toggle class="follow-toggle"> <span class="follow">Follow</span> <span class="following">Following</span> </sv-toggle></div>
<style> .toggle-content-container {19 collapsed lines
--anim-dur: 400ms; --anim-ease: cubic-bezier(0.486, 1.45, 0.2, 1);
display: flex; flex-direction: column; gap: 1em; align-items: center;
.icon { display: block; grid-area: 1 / 1; inline-size: 1.2em; block-size: 1.2em; fill: currentcolor; }
@media (prefers-reduced-motion: reduce) { --anim-dur: 0s; } }
.favorite-toggle {14 collapsed lines
display: inline-grid; place-items: center; padding: 0.4em;
.icon { transition: scale var(--anim-dur) var(--anim-ease), rotate var(--anim-dur) var(--anim-ease); }
.icon.filled { rotate: -90deg; scale: 0; }
&:state(--pressed) { .icon.filled { rotate: 0deg; scale: 1; }
.icon.outline { rotate: 90deg; scale: 0; } } }
.mute-toggle {17 collapsed lines
gap: 0.4em;
.icon-stack { display: grid; place-items: center; }
.icon { transition: opacity var(--anim-dur) ease, scale var(--anim-dur) var(--anim-ease); }
.icon.volume-off { opacity: 0; scale: 0.6; }
&:state(--pressed) { .icon.volume-on { opacity: 0; scale: 0.6; }
.icon.volume-off { opacity: 1; scale: 1; } } }
.follow-toggle {12 collapsed lines
display: inline-grid; place-items: center;
/* Both labels share the same cell, so the button keeps the width of the widest one */ .follow, .following { grid-area: 1 / 1; }
.following { visibility: hidden; }
&:state(--pressed) { .follow { visibility: hidden; }
.following { visibility: visible; } } }</style>