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 &#34;Read less&#34; initially and will switch to &#34;Read more&#34; 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>&#34;Great product that works exactly as advertised. I was up and running in minutes with zero configuration
                    needed.&#34;</p>
            </brio-clamp-text>
        </div>
        <div class="card">
            <h3>Long testimonial</h3>
            <brio-clamp-text lines="4">
                <p>&#34;I&#39;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&#39;ve already recommended this to all my colleagues and friends without
                    hesitation.&#34;</p>
            </brio-clamp-text>
        </div>
        <div class="card">
            <h3>Medium testimonial</h3>
            <brio-clamp-text lines="4">
                <p>&#34;Solid choice overall. The onboarding process was surprisingly smooth and whenever I had questions, the
                    support team responded quickly with helpful answers.&#34;</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.

<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&#39;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(&#39;manual-clamp&#39;); var isExpanded = el.getAttribute(&#39;aria-expanded&#39;) === &#39;true&#39;; el.setAttribute(&#39;aria-expanded&#39;, String(!isExpanded)); this.textContent = isExpanded ? &#39;Read more&#39; : &#39;Read less&#39;;">
            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-expanded on the host and aria-controls on 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

TokenDefaultDescription
--clamp-lines3Number of lines to display when clamped
--clamp-fade-heightcalc(0.5em * var(--clamp-lines))Height of the fade gradient at the bottom
--clamp-fade-colorvar(--color-surface, oklch(100% 0 0))Color of the fade gradient -- matches background by default

Classes

ClassDescription
.clamp-textcomponent root
.is-1-lineClamp to 1 line
.is-2-linesClamp to 2 lines
.is-3-linesClamp to 3 lines (default)
.is-4-linesClamp to 4 lines
.is-5-linesClamp to 5 lines
.is-responsiveResponsive clamping -- no default, meant to be customized