Clamp-text
Part of the extras bundle, not included by default.
Intent
Clamp long text to a fixed number of lines with a subtle gradient fade at the bottom, then let the user reveal the rest with a toggle. Useful for testimonials, comments, product descriptions, or any content where uniform card heights improve the layout but full text should remain accessible on demand.
The default fade spans ~1.5em for a 3-line clamp (0.5em per line),
scaling with --clamp-lines. Override
--clamp-fade-color when the component sits on a
non-default surface so the fade blends into its background.
Basic usage
Wrap content in <brio-clamp-text> and set
lines to the number of lines you want visible before
clamping. The component auto-renders a toggle button.
This text is clamped to three lines with a subtle gradient fade at the bottom. Clicking the toggle reveals the rest of the content. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
<docs-resize>
<brio-clamp-text lines="3">
<p>This text is clamped to three lines with a subtle gradient fade at the bottom. Clicking the toggle reveals the
rest of the content. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur.</p>
</brio-clamp-text>
</docs-resize>Line counts
Change the visible line count with the lines attribute,
or use the .is-N-lines helper classes for CSS-only
variants. The fade height scales automatically: 0.5em per
clamped line.
Two-line clamp with a shorter fade. This text demonstrates how the gradient fade adjusts based on the line count. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco.
Four-line clamp with a taller fade area. The gradient spans approximately twice as much space as the two-line version. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor. In reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor. In reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
<docs-resize>
<div class="stack">
<brio-clamp-text lines="2">
<p>Two-line clamp with a shorter fade. This text demonstrates how the gradient fade adjusts based on the line
count. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore
et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco.</p>
</brio-clamp-text>
<brio-clamp-text lines="4">
<p>Four-line clamp with a taller fade area. The gradient spans approximately twice as much space as the two-line
version. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore
et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
ex ea commodo consequat. Duis aute irure dolor. In reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt
mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor. In reprehenderit in voluptate velit
esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa
qui officia deserunt mollit anim id est laborum.
</p>
</brio-clamp-text>
</div>
</docs-resize>Custom toggle button
Slot a button with data-clamp-toggle to replace the
auto-generated toggle. The component handles ARIA state and
click behavior; you control the styling and text.
Long text with a custom-styled toggle button. The component finds the slotted button via data-clamp-toggle and manages its ARIA state and text automatically. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.
<docs-resize>
<brio-clamp-text lines="3">
<p>Long text with a custom-styled toggle button. The component finds the slotted button via data-clamp-toggle and
manages its ARIA state and text automatically. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo.</p>
<button class="button is-sm is-primary" data-clamp-toggle="">Read more</button>
</brio-clamp-text>
</docs-resize>Toggle text
The auto-generated toggle switches between "Read more" and "Read
less" automatically. Override the defaults with
read-more and read-less attributes,
or provide your own text in a slotted button.
Custom toggle text via read-more and read-less attributes. The button text automatically updates between your custom labels. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip.
<docs-resize>
<brio-clamp-text lines="3" read-more="Show more" read-less="Show less">
<p>Custom toggle text via read-more and read-less attributes. The button text automatically updates between your
custom labels. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip.</p>
</brio-clamp-text>
</docs-resize>Initially expanded
Start in the expanded state with expanded="true".
Useful when the full text is the default but clamping is an
optional space-saver.
Starts in the expanded state. The toggle button reads "Read less" initially and will switch to "Read more" when clicked. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
<docs-resize>
<brio-clamp-text lines="3" expanded="true">
<p>Starts in the expanded state. The toggle button reads "Read less" initially and will switch to "Read more" when
clicked. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat.</p>
</brio-clamp-text>
</docs-resize>Testimonial grid
Equal-height cards with clamped text and toggles. Short and long testimonials render at the same height until expanded.
Short testimonial
"Great product that works exactly as advertised. I was up and running in minutes with zero configuration needed."
Long testimonial
"I've been using this for six months and it has completely transformed my entire workflow. The team is incredibly responsive to questions and feature requests, the documentation is crystal clear, and the API is an absolute joy to work with. I've already recommended this to all my colleagues and friends without hesitation."
Medium testimonial
"Solid choice overall. The onboarding process was surprisingly smooth and whenever I had questions, the support team responded quickly with helpful answers."
<docs-resize>
<div class="grid" style="--grid-columns: repeat(auto-fill, minmax(280px, 1fr)); --gap: var(--space-md)">
<div class="card">
<h3>Short testimonial</h3>
<brio-clamp-text lines="4">
<p>"Great product that works exactly as advertised. I was up and running in minutes with zero configuration
needed."</p>
</brio-clamp-text>
</div>
<div class="card">
<h3>Long testimonial</h3>
<brio-clamp-text lines="4">
<p>"I've been using this for six months and it has completely transformed my entire workflow. The team is
incredibly responsive to questions and feature requests, the documentation is crystal clear, and the API
is an absolute joy to work with. I've already recommended this to all my colleagues and friends without
hesitation."</p>
</brio-clamp-text>
</div>
<div class="card">
<h3>Medium testimonial</h3>
<brio-clamp-text lines="4">
<p>"Solid choice overall. The onboarding process was surprisingly smooth and whenever I had questions, the
support team responded quickly with helpful answers."</p>
</brio-clamp-text>
</div>
</div>
</docs-resize>On non-white backgrounds
Inside a card or other elevated surface, the fade needs to match
the container background. Override
--clamp-fade-color on the component or a parent
scope.
This clamp-text sits on a card surface with a raised background. The fade gradient blends into the card background by overriding --clamp-fade-color to match. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud.
<docs-resize>
<div class="card" style="--clamp-fade-color: var(--color-surface-raised)">
<brio-clamp-text lines="3">
<p>This clamp-text sits on a card surface with a raised background. The fade gradient blends into the card
background by overriding --clamp-fade-color to match. Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud.</p>
</brio-clamp-text>
</div>
</docs-resize>Class-only usage (no JS)
The CSS works standalone. Manage aria-expanded yourself
for full functionality; the CSS responds to the attribute.
CSS-only clamp without the custom element. The visual clamping and fade are applied via CSS. Without JS, the button won't toggle automatically, but you can manage aria-expanded yourself as shown here. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.
<docs-resize>
<div class="clamp-text" style="--clamp-lines: 3" aria-expanded="false" id="manual-clamp">
<p class="clamp-text-content">CSS-only clamp without the custom element. The visual clamping and fade are
applied via CSS. Without JS, the button won't toggle automatically, but you can manage aria-expanded
yourself as shown here. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.</p>
<button class="button is-sm clamp-text-toggle" onclick="var el = document.getElementById('manual-clamp'); var isExpanded = el.getAttribute('aria-expanded') === 'true'; el.setAttribute('aria-expanded', String(!isExpanded)); this.textContent = isExpanded ? 'Read more' : 'Read less';">
Read more
</button>
</div>
</docs-resize>Programmatic access
The component emits brio:clamp-toggle on the host when
the user toggles. Listen for it to react to state changes, or
read aria-expanded directly.
document.querySelector("brio-clamp-text")
.addEventListener("brio:clamp-toggle", (e) => {
console.log(e.detail.expanded); // true or false
});
// Or import the class directly from the extras bundle:
import { BrioClampText } from "/assets/brio-extras.js";
// Or use the global namespace from non-module contexts:
const instance = document.querySelector("brio-clamp-text");
console.log(instance.getAttribute("aria-expanded"));
Customization
Line count, fade height, and fade color flow through scoped
--clamp-* tokens. Override them on the component or
a parent scope.
Custom fade height (2em instead of the default 1.5em) and a light gray fade color. Override --clamp-fade-height and --clamp-fade-color for custom effects. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation.
<docs-resize>
<brio-clamp-text lines="3" style="--clamp-fade-height: 2em; --clamp-fade-color: oklch(90% 0 0)">
<p>Custom fade height (2em instead of the default 1.5em) and a light gray fade color. Override --clamp-fade-height
and --clamp-fade-color for custom effects. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
exercitation.</p>
</brio-clamp-text>
</docs-resize>Accessibility
-
ARIA state. The component manages
aria-expandedon the host andaria-controlson the toggle, pointing to the content element's ID. Screen readers announce the expanded / collapsed state automatically. -
Keyboard. The toggle is a native
<button>and reaches the tab order. Space and Enter both activate it. - Focus. When expanded or collapsed via click, focus returns to the toggle so keyboard users can immediately interact with it again.
Markup
<!-- Auto toggle -->
<brio-clamp-text lines="3">
<p>Long text...</p>
</brio-clamp-text>
<!-- Custom toggle with your own button -->
<brio-clamp-text lines="3">
<p>Long text...</p>
<button class="button is-primary" data-clamp-toggle>Read more</button>
</brio-clamp-text>
<!-- Initially expanded -->
<brio-clamp-text lines="3" expanded="true">
<p>Long text...</p>
</brio-clamp-text>
<!-- Custom text labels -->
<brio-clamp-text lines="3" read-more="Show more" read-less="Hide">
<p>Long text...</p>
</brio-clamp-text>
<!-- CSS-only (manage aria-expanded yourself) -->
<div class="clamp-text" style="--clamp-lines: 3" aria-expanded="false">
<p class="clamp-text-content">Long text...</p>
<button class="clamp-text-toggle">Read more</button>
</div>
CSS Reference: Clamp Text
Multi-line clamp with fade and toggle
Source: src/css/extras/clamp-text.css
Tokens
| Token | Default | Description |
|---|---|---|
--clamp-lines | 3 | Number of lines to display when clamped |
--clamp-fade-height | calc(0.5em * var(--clamp-lines)) | Height of the fade gradient at the bottom |
--clamp-fade-color | var(--color-surface, oklch(100% 0 0)) | Color of the fade gradient -- matches background by default |
Classes
| Class | Description |
|---|---|
.clamp-text | component root |
.is-1-line | Clamp to 1 line |
.is-2-lines | Clamp to 2 lines |
.is-3-lines | Clamp to 3 lines (default) |
.is-4-lines | Clamp to 4 lines |
.is-5-lines | Clamp to 5 lines |
.is-responsive | Responsive clamping -- no default, meant to be customized |