Skip to content

Segmented Control Examples

The examples below assume that you have imported the component and set up the theme.

Basic

Each option is a plain button with a value, and value on the control picks the selected one. Arrow keys move between the options.

<sv-segmented-control class="segmented-basic" aria-label="Choose a plan" value="business">
<button value="personal">Personal</button>
<button value="business">Business</button>
<button value="enterprise">Enterprise</button>
</sv-segmented-control>
<style>
.segmented-basic {
max-inline-size: 24rem;
margin-inline: auto;
button {
font: inherit;
font-weight: 600;
}
/* Vertically stack buttons on small screens */
@media (max-width: 430px) {
--sv-segmented-control-flex-dir: column;
}
}
</style>

Disabled

disabled on a button skips that option, and on the control blocks the whole group.

disabled button
disabled
<div class="segmented-states">
<div class="variant">
<sv-segmented-control aria-label="Disabled option" value="all">
<button value="all">All</button>
<button value="unread">Unread</button>
<button disabled value="archived">Archived</button>
</sv-segmented-control>
<span>disabled button</span>
</div>
<div class="variant">
<sv-segmented-control aria-label="Disabled control" disabled value="unread">
<button value="all">All</button>
<button value="unread">Unread</button>
<button value="archived">Archived</button>
</sv-segmented-control>
<span>disabled</span>
</div>
</div>
<style>
.segmented-states {
display: grid;
gap: 1.5em;
max-inline-size: 24rem;
padding-block: 1em;
margin-inline: auto;
.variant {
display: grid;
gap: 0.4em;
span {
justify-self: center;
font-size: 0.8em;
color: var(--sv-gray-3);
}
}
button {
font: inherit;
font-weight: 600;
}
/* Vertically stack buttons on small screens */
@media (max-width: 400px) {
sv-segmented-control {
--sv-segmented-control-flex-dir: column;
}
}
}
</style>

Orientation

vertical stacks the buttons in a column. --sv-segmented-control-flex-dir takes any flex-direction value and overrides the attribute wherever it is set.

vertical
--sv-segmented-control-flex-dir: row-reverse
<div class="segmented-orientation">
<div class="variant">
<sv-segmented-control aria-label="Vertical alignment" value="center" vertical>
<button value="start">Start</button>
<button value="center">Center</button>
<button value="end">End</button>
</sv-segmented-control>
<span>vertical</span>
</div>
<div class="variant">
<sv-segmented-control class="reversed" aria-label="Reversed order" value="center">
<button value="start">Start</button>
<button value="center">Center</button>
<button value="end">End</button>
</sv-segmented-control>
<span>--sv-segmented-control-flex-dir: row-reverse</span>
</div>
</div>
<style>
.segmented-orientation {
display: grid;
gap: 1.5em;
max-inline-size: 24rem;
padding-block: 1em;
margin-inline: auto;
.variant {
display: grid;
gap: 0.4em;
justify-items: center;
span {
font-size: 0.8em;
color: var(--sv-gray-3);
}
}
button {
font: inherit;
font-weight: 600;
}
.reversed {
--sv-segmented-control-flex-dir: row-reverse;
justify-self: stretch;
}
}
</style>

Icons

The buttons are yours, so any markup goes inside them. Styling them is done in your own stylesheet, not through parts.

<sv-segmented-control class="segmented-icons" aria-label="Choose a device" value="pc">
<button value="laptop">
<!-- Laptop -->
<svg aria-hidden="true" viewBox="0 0 24 24">
<path d="M20 18c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2H0v2h24v-2zM4 6h16v10H4z"></path>
</svg>
Laptop
</button>
<button value="pc">
<!-- Desktop -->
<svg aria-hidden="true" viewBox="0 0 24 24">
<path d="M21 3H3c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h5v2h8v-2h5c1.1 0 1.99-.9 1.99-2L23 5c0-1.1-.9-2-2-2m0 14H3V5h18z"></path>
</svg>
PC
</button>
<button value="phone">
<!-- Phone -->
<svg aria-hidden="true" viewBox="0 0 24 24">
<path
d="M16 1H8C6.34 1 5 2.34 5 4v16c0 1.66 1.34 3 3 3h8c1.66 0 3-1.34 3-3V4c0-1.66-1.34-3-3-3m-2 20h-4v-1h4zm3.25-3H6.75V4h10.5z"
></path>
</svg>
Phone
</button>
</sv-segmented-control>
<style>
.segmented-icons {
max-inline-size: 24rem;
margin-inline: auto;
button {
display: flex;
gap: 0.5em;
align-items: center;
justify-content: center;
font: inherit;
font-weight: 600;
svg {
inline-size: 1.2em;
block-size: 1.2em;
fill: currentcolor;
}
}
/* Vertically stack buttons on small screens */
@media (max-width: 440px) {
--sv-segmented-control-flex-dir: column;
button {
justify-content: start;
}
}
}
</style>

Styling

The color tokens tint the indicator, --sv-segmented-control-bdr-rad rounds the container and the indicator together, and --sv-segmented-control-pad is the gap between the container edge and the buttons.

--sv-segmented-control-active-bg
--sv-segmented-control-bdr-rad
--sv-segmented-control-pad: 0px
<div class="segmented-styling">
<div class="variant">
<sv-segmented-control class="tinted" aria-label="Tinted" value="week">
<button value="day">Day</button>
<button value="week">Week</button>
<button value="month">Month</button>
</sv-segmented-control>
<span>--sv-segmented-control-active-bg</span>
</div>
<div class="variant">
<sv-segmented-control class="pill" aria-label="Pill shaped" value="week">
<button value="day">Day</button>
<button value="week">Week</button>
<button value="month">Month</button>
</sv-segmented-control>
<span>--sv-segmented-control-bdr-rad</span>
</div>
<div class="variant">
<sv-segmented-control class="tight" aria-label="No padding" value="week">
<button value="day">Day</button>
<button value="week">Week</button>
<button value="month">Month</button>
</sv-segmented-control>
<span>--sv-segmented-control-pad: 0px</span>
</div>
</div>
<style>
.segmented-styling {
display: grid;
gap: 1.5em;
max-inline-size: 24rem;
padding-block: 1em;
margin-inline: auto;
.variant {
display: grid;
gap: 0.4em;
span {
justify-self: center;
font-size: 0.8em;
color: var(--sv-gray-3);
}
}
button {
font: inherit;
font-weight: 600;
}
.tinted {
--sv-segmented-control-active-bg: #22c55e;
}
.pill {
--sv-segmented-control-bdr-rad: 999px;
}
.tight {
--sv-segmented-control-pad: 0px;
}
/* Vertically stack buttons on small screens */
@media (max-width: 345px) {
sv-segmented-control {
--sv-segmented-control-flex-dir: column;
}
}
}
</style>

Animation

--sv-segmented-control-dur and --sv-segmented-control-ease drive the indicator slide. setValue() can override both per call, and the reduced motion fallback wins over both.

Reduced Motion

Your system is set to reduce motion, so this animation will not play for you.

--sv-segmented-control-dur: 900ms
--sv-segmented-control-ease: linear
--sv-segmented-control-dur: 0s
<div class="segmented-animation">
<div class="variant">
<sv-segmented-control class="slow" aria-label="Slow indicator" value="low">
<button value="low">Low</button>
<button value="medium">Medium</button>
<button value="high">High</button>
</sv-segmented-control>
<span>--sv-segmented-control-dur: 900ms</span>
</div>
<div class="variant">
<sv-segmented-control class="linear" aria-label="Linear indicator" value="low">
<button value="low">Low</button>
<button value="medium">Medium</button>
<button value="high">High</button>
</sv-segmented-control>
<span>--sv-segmented-control-ease: linear</span>
</div>
<div class="variant">
<sv-segmented-control class="instant" aria-label="Instant indicator" value="low">
<button value="low">Low</button>
<button value="medium">Medium</button>
<button value="high">High</button>
</sv-segmented-control>
<span>--sv-segmented-control-dur: 0s</span>
</div>
</div>
<style>
.segmented-animation {
display: grid;
gap: 1.5em;
max-inline-size: 24rem;
padding-block: 1em;
margin-inline: auto;
.variant {
display: grid;
gap: 0.4em;
span {
justify-self: center;
font-size: 0.8em;
color: var(--sv-gray-3);
}
}
button {
font: inherit;
font-weight: 600;
}
.slow {
--sv-segmented-control-dur: 900ms;
}
.linear {
--sv-segmented-control-ease: linear;
}
.instant {
--sv-segmented-control-dur: 0s;
}
/* Vertically stack buttons on small screens */
@media (max-width: 380px) {
sv-segmented-control {
--sv-segmented-control-flex-dir: column;
}
}
@media (prefers-reduced-motion: reduce) {
.slow {
--sv-segmented-control-dur: 0s;
}
}
}
</style>