Skip to content

Toggle Group Custom Style

Three different looks built only with CSS on the host elements: a connected pill toolbar, multi-select filter chips with an animated checkmark, and an exclusive group with an animated underline. Non-toggle elements inside the groups, like the dividers here, are ignored by the group’s logic. The pill group is a bar of controls, so it carries role="toolbar".

Pill Left Center Right
Chips HTML CSS JavaScript
UnderlineDayWeekMonthYear

Code

The following example assumes that you have imported the components and set up the theme.

Toggle Group Custom Style
<div class="toggle-style-container">
<!-- Pill toolbar -->
<div class="style-column">
<span id="pill-label">Pill</span>
<sv-toggle-group class="pill" role="toolbar" aria-labelledby="pill-label" exclusive value="left">
<sv-toggle value="left">
5 collapsed lines
<svg class="icon" aria-hidden="true" viewBox="0 -960 960 960" xmlns="http://www.w3.org/2000/svg">
<path
d="M120-120v-80h720v80H120Zm0-160v-80h480v80H120Zm0-160v-80h720v80H120Zm0-160v-80h480v80H120Zm0-160v-80h720v80H120Z"
></path>
</svg>
Left
</sv-toggle>
<span class="divider" aria-hidden="true"></span>
<sv-toggle value="center">
5 collapsed lines
<svg class="icon" aria-hidden="true" viewBox="0 -960 960 960" xmlns="http://www.w3.org/2000/svg">
<path
d="M120-120v-80h720v80H120Zm160-160v-80h400v80H280ZM120-440v-80h720v80H120Zm160-160v-80h400v80H280ZM120-760v-80h720v80H120Z"
></path>
</svg>
Center
</sv-toggle>
<span class="divider" aria-hidden="true"></span>
<sv-toggle value="right">
5 collapsed lines
<svg class="icon" aria-hidden="true" viewBox="0 -960 960 960" xmlns="http://www.w3.org/2000/svg">
<path
d="M120-760v-80h720v80H120Zm240 160v-80h480v80H360ZM120-440v-80h720v80H120Zm240 160v-80h480v80H360ZM120-120v-80h720v80H120Z"
></path>
</svg>
Right
</sv-toggle>
</sv-toggle-group>
</div>
<!-- Filter chips -->
<div class="style-column">
<span id="chips-label">Chips</span>
<sv-toggle-group class="chips" aria-labelledby="chips-label" value="css javascript">
<sv-toggle value="html">
<span class="check" aria-hidden="true"></span>
HTML
</sv-toggle>
<sv-toggle value="css">
<span class="check" aria-hidden="true"></span>
CSS
</sv-toggle>
<sv-toggle value="javascript">
<span class="check" aria-hidden="true"></span>
JavaScript
</sv-toggle>
</sv-toggle-group>
</div>
<!-- Animated underline -->
<div class="style-column">
<span id="underline-label">Underline</span>
<sv-toggle-group class="underline-group" aria-labelledby="underline-label" exclusive value="week">
<sv-toggle value="day">Day</sv-toggle>
<span class="divider" aria-hidden="true"></span>
<sv-toggle value="week">Week</sv-toggle>
<span class="divider" aria-hidden="true"></span>
<sv-toggle value="month">Month</sv-toggle>
<span class="divider" aria-hidden="true"></span>
<sv-toggle value="year">Year</sv-toggle>
</sv-toggle-group>
</div>
</div>
<style>
.toggle-style-container {
9 collapsed lines
display: grid;
gap: 2em;
justify-content: center;
.divider {
inline-size: var(--sv-bdr-sz-sm);
block-size: 1.2em;
background-color: var(--sv-gray-5);
}
}
.style-column {
4 collapsed lines
display: flex;
flex-direction: column;
gap: 0.5rem;
align-items: flex-start;
}
.pill {
4 collapsed lines
align-items: stretch;
overflow: clip;
background-color: var(--sv-gray-6);
border-radius: calc(infinity * 1px);
sv-toggle {
20 collapsed lines
--tint: color-mix(in srgb, var(--sv-accent) 15%, transparent);
gap: 0.4em;
padding: 0.6em 1.4em;
background-color: transparent;
background-image: linear-gradient(var(--tint), var(--tint));
background-repeat: no-repeat;
background-position: center;
background-size: 0% 100%;
border: none;
border-radius: 0;
transition:
background-size var(--sv-dur) var(--sv-ease),
color var(--sv-dur) var(--sv-ease);
.icon {
inline-size: 1.2em;
block-size: 1.2em;
fill: currentcolor;
}
&:state(--pressed) {
color: var(--sv-accent);
background-color: transparent;
background-size: 100% 100%;
}
}
.divider {
block-size: auto;
}
}
.chips {
gap: 0.5rem;
sv-toggle {
13 collapsed lines
padding: 0.4em 0.9em;
background-color: transparent;
border-color: var(--sv-gray-4);
border-radius: var(--sv-bdr-rad-sm);
.check {
inline-size: 0;
overflow: hidden;
opacity: 0;
transition:
inline-size var(--sv-dur) var(--sv-ease),
opacity var(--sv-dur) var(--sv-ease);
}
&:state(--pressed) {
color: var(--sv-accent);
background-color: color-mix(in srgb, var(--sv-accent) 12%, transparent);
border-color: var(--sv-accent);
.check {
inline-size: 1.1em;
opacity: 1;
}
}
}
}
.underline-group {
gap: 0.5rem;
align-items: center;
sv-toggle {
10 collapsed lines
padding: 0.4em 0.2em;
color: var(--sv-gray-3);
background-color: transparent;
background-image: linear-gradient(var(--sv-accent), var(--sv-accent));
background-repeat: no-repeat;
background-position: bottom center;
background-size: 0% var(--sv-bdr-sz-md);
border: none;
border-radius: 0;
transition-property: color, background-size;
&:state(--pressed) {
color: var(--sv-gray-0);
background-color: transparent;
background-size: 100% var(--sv-bdr-sz-md);
}
}
}
</style>