Skip to content

Show More

An article clipped to its opening paragraph, with a button below that reveals the rest. The trigger slot renders above the expander, so a trigger that belongs below the content is placed after the collapsible and named with trigger-element instead. The collapsible carries the --opened state, so the fading mask on the teaser and the button's label swap are plain CSS on :has(:state(--opened)), with no script involved. Both labels share one grid cell, so the button keeps its size when the label swaps.

Design tokens that survive a rebrand

Design tokens promise a single source of truth for color, spacing, and type, yet most token sets quietly hard-code the current brand into their names. When the palette changes, every component that referenced a token by its color name has to be touched again.

Naming by role instead of appearance is what makes a token set durable. A token called accent or surface can take any value a rebrand throws at it, while one called blue-500 is a migration waiting to happen.

The same discipline applies to spacing and type ramps. Name the steps by their job, keep the scale short, and a rebrand becomes a one-file change instead of a repo-wide search.

Code

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

Show More
<article class="show-more">
23 collapsed lines
<h2>Design tokens that survive a rebrand</h2>
<p class="teaser">
Design tokens promise a single source of truth for color, spacing, and type, yet most token sets quietly hard-code the current
brand into their names. When the palette changes, every component that referenced a token by its color name has to be touched
again.
</p>
<sv-collapsible class="rest" trigger-element=".more-trigger">
<p>
Naming by role instead of appearance is what makes a token set durable. A token called accent or surface can take any value
a rebrand throws at it, while one called blue-500 is a migration waiting to happen.
</p>
<p>
The same discipline applies to spacing and type ramps. Name the steps by their job, keep the scale short, and a rebrand
becomes a one-file change instead of a repo-wide search.
</p>
</sv-collapsible>
<button type="button" class="more-trigger">
<span class="more">Show more</span>
<span class="less">Show less</span>
</button>
</article>
<style>
52 collapsed lines
.show-more {
inline-size: min(34rem, 100%);
padding-block: 1em;
margin-inline: auto;
color: var(--sv-gray-2);
h2 {
margin-block: 0 0.5em;
font-size: 1.2rem;
color: var(--sv-gray-1);
}
p {
margin-block: 0 0.75em;
line-height: 1.6;
}
&:not(:has(.rest:state(--opened))) .teaser {
mask-image: linear-gradient(#000 40%, transparent);
}
.more-trigger {
display: inline-grid;
place-items: center;
padding: 0.4em 0.2em;
font: inherit;
font-weight: 600;
color: var(--sv-accent);
cursor: pointer;
background: none;
border: none;
.more,
.less {
grid-area: 1 / 1;
}
.less {
visibility: hidden;
}
}
&:has(.rest:state(--opened)) .more-trigger {
.more {
visibility: hidden;
}
.less {
visibility: visible;
}
}
}
</style>