A .show-more cuts long text to a few lines and adds a button that shows the rest.
Put the text in a child with a line clamp class,
line-clamp-1, line-clamp-2 or line-clamp-3, and add a
<button type="button"> whose text is the collapsed label.
AutoInit() starts every one. The button gets aria-expanded and an
aria-controls that names the text, and the component adds an id to the text when it has none.
This jacket is cut from a recycled shell that sheds light rain and packs into its own chest pocket. A brushed lining keeps it warm on cool mornings without the bulk of insulation, and two zipped hand pockets hold a phone and keys. The hood folds into the collar when you don't need it, and the cuffs close with a soft stretch band.
<div class="show-more">
<p class="line-clamp-3">This jacket is cut from a recycled shell that sheds light rain...</p>
<button type="button" class="text">Show more</button>
</div>
The button's label
While the text is open, the button reads "Show less". data-show-less on the button
sets that label for one control, and the i18n.showLess option sets it for the component.
Closing the text puts the author's label back. Only the button's last text outside an
aria-hidden="true" element changes, so an icon keeps its glyph. An icon-only
button named by aria-label has no text to change: it keeps its name, and only
aria-expanded says the text is open. Prefer a visible label.
<div class="show-more">
<p class="line-clamp-2">...</p>
<button type="button" class="text" data-show-less="Fewer details">
More details
<span class="material-symbols" aria-hidden="true">expand_more</span>
</button>
</div>
Text that already fits
While the clamped text fits, the button gets hidden, so it is neither seen nor reached
by Tab. The component checks again when the text's size changes and once web fonts have loaded.
With a window-size prefix, line-clamp-3 expanded:line-clamp-none clamps on compact
and medium windows and hides the button from Expanded up. Open text keeps its button, and a
focused button stays until focus moves on.
Limits
The clamp classes set display, so the text cannot also be a flex or grid container.
The browser's find-in-page does not open clamped text, so a match in the hidden lines is not
shown until the person opens it. The text opens and closes at once, without a transition.
Methods
const more = Expressive.ShowMore.getInstance(document.querySelector('.show-more'));
more.open(); // shows the full text and fires expressive:open
more.close(); // clamps it again and fires expressive:close
more.destroy(); // removes the listeners and restores the markup