Type something to search...
How to Use the CSS line-clamp Property to Truncate Text?

How to Use the CSS line-clamp Property to Truncate Text?

Your blog grid looks great in the design file, where every card has a two-line title and a three-line excerpt. Then real content arrives. One editor writes a seven-word headline, another writes twenty-two words, and the excerpts range from a single sentence to a full paragraph. The cards end up with wildly different heights, the "Read more" buttons no longer line up, and the grid looks broken. You need every excerpt to stop at exactly three lines and end with an ellipsis, regardless of how long the text is or how wide the card renders.

That is what line-clamp does. This article explains how it works, the exact CSS you need in 2026, how to build an accessible expand/collapse toggle, how to detect whether text was truncated, and the padding, flexbox, and accessibility pitfalls to watch for.

What Is line-clamp?

Line clamping limits a block of text to a specific number of lines and hides the rest, usually adding an ellipsis (…) at the end of the last visible line. Unlike a fixed max-height, a clamp is measured in lines, so it adapts automatically to font size, line height, and container width.

There are two related techniques:

TechniqueLinesKey properties
Single-line truncation1white-space: nowrap, overflow: hidden, text-overflow: ellipsis
Multi-line clamping2+-webkit-line-clamp with display: -webkit-box

Single-Line Truncation with text-overflow

For one line, you do not need line-clamp at all. The classic three-property pattern has worked in every browser for over a decade:

.truncate {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

This is ideal for file names, email subjects in a list, table cells, and breadcrumb items. It requires the element to have a constrained width, either explicitly or through its layout. Inside a flex container, add min-width: 0 to the flex item, because flex items default to min-width: auto and will refuse to shrink below their content width:

.file-row {
  display: flex;
  gap: 0.75rem;
}

.file-row .name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

Multi-Line Clamping: The Working CSS

For two or more lines, use the -webkit-line-clamp property. Despite the prefix, it is supported in Chrome, Edge, Safari, and Firefox, and the prefixed form is what the specification itself documents for compatibility. It only works in combination with two other legacy declarations:

.excerpt {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
}

All four lines are required:

  1. display: -webkit-box switches the element into the legacy flexible box model that the clamp depends on.
  2. -webkit-box-orient: vertical stacks content vertically.
  3. -webkit-line-clamp: 3 sets the number of lines.
  4. overflow: hidden hides everything after the clamp.

Leave out any one of them and the clamp silently fails. The ellipsis is added automatically; you do not need text-overflow.

What About the Unprefixed line-clamp?

The CSS Overflow Module Level 4 defines an unprefixed line-clamp shorthand that will eventually work without the legacy display value. Browser support for the unprefixed version is still incomplete, so ship the prefixed pattern and optionally add the standard property alongside it for the future:

.excerpt {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
}

Browsers that do not understand line-clamp ignore it, and the prefixed declaration does the work.

Making the Clamp Reusable

Hard-coding a line count in each component gets repetitive. A custom property makes the clamp configurable per instance:

.clamp {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: var(--clamp-lines, 3);
  line-clamp: var(--clamp-lines, 3);
  overflow: hidden;
}
<h3 class="clamp" style="--clamp-lines: 2">A very long article title that might wrap</h3>
<p class="clamp" style="--clamp-lines: 4">An excerpt that should stop after four lines...</p>

In Tailwind CSS v4

Line clamping is built into Tailwind v4 core. Use line-clamp-1 through line-clamp-6, arbitrary values like line-clamp-[8], and line-clamp-none to remove it. Single-line truncation is truncate.

type PostCardProps = { title: string; excerpt: string; href: string };

export function PostCard({ title, excerpt, href }: PostCardProps) {
  return (
    <article className="flex flex-col rounded-lg border p-6">
      <h3 className="text-xl font-semibold line-clamp-2">
        <a href={href}>{title}</a>
      </h3>
      <p className="mt-3 text-base line-clamp-3">{excerpt}</p>
      <a href={href} className="mt-auto pt-4 font-medium">
        Read more
      </a>
    </article>
  );
}

Responsive variants work too: line-clamp-2 md:line-clamp-4 shows more text on wider screens.

The Padding Pitfall

The most common line-clamp bug is the "peeking" next line. If you put vertical padding on the clamped element, the hidden fourth line shows through inside the bottom padding, because overflow: hidden clips at the padding box, not the content box.

/* Buggy: part of line 4 is visible in the bottom padding */
.excerpt {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
  padding-block: 1rem;
}

The fix is to keep padding off the clamped element. Put it on a wrapper instead:

<div class="excerpt-wrapper">
  <p class="excerpt">...</p>
</div>
.excerpt-wrapper {
  padding-block: 1rem;
}

The same applies to borders and backgrounds that you expect to hug the visible text. Style the wrapper, clamp the text.

Other Gotchas

Clamp a Single Text Block

Line clamping is most reliable on one element containing inline content, such as a p or h3. If you clamp a container with several block children (multiple paragraphs, a heading and a paragraph), results vary between browsers and the ellipsis may not appear where you expect. Clamp the text element itself.

Inline Elements Inside the Clamp

Links, strong, and em inside the clamped text work fine. Inline images, badges, and icons can push line boxes taller and change where the clamp falls. Keep decorative inline elements outside the clamped element where possible.

Line Height Must Be Consistent

The clamp counts line boxes, not pixels. If the text mixes font sizes, lines have different heights and cards will no longer align. Use a consistent line-height on clamped elements. If you need to reserve space so short excerpts still occupy three lines, the lh unit gives you exactly one line height:

.excerpt {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
  line-height: 1.5;
  min-height: 3lh; /* always occupy three lines, even with a short excerpt */
}

A max-height Fallback

If you ever need to support an environment without -webkit-line-clamp (some email clients, some embedded webviews), clip with max-height. You lose the ellipsis but keep the layout:

@supports not (-webkit-line-clamp: 3) {
  .excerpt {
    max-height: 3lh;
    overflow: hidden;
  }
}

Building an Accessible Read-More Toggle

Clamping only hides text visually. Screen readers still read the full content, which is usually what you want. But sighted users also need a way to see it. For expandable content such as reviews or descriptions, add a toggle button:

<div class="review">
  <p id="review-42" class="clamp" style="--clamp-lines: 4">
    The full review text goes here, however long it is...
  </p>
  <button type="button" class="toggle" aria-expanded="false" aria-controls="review-42" hidden>
    Show more
  </button>
</div>
.clamp.is-expanded {
  -webkit-line-clamp: unset;
  line-clamp: none;
}
document.querySelectorAll(".review").forEach((review) => {
  const text = review.querySelector(".clamp");
  const button = review.querySelector(".toggle");

  // Only show the button if the text is actually truncated
  const isTruncated = text.scrollHeight > text.clientHeight + 1;
  if (!isTruncated) return;

  button.hidden = false;
  button.addEventListener("click", () => {
    const expanded = text.classList.toggle("is-expanded");
    button.setAttribute("aria-expanded", String(expanded));
    button.textContent = expanded ? "Show less" : "Show more";
  });
});

Key accessibility points:

  • Use a real button, not a link or a clickable span, so it is focusable and keyboard-operable.
  • Set aria-expanded so screen reader users know the state.
  • Hide the button when nothing is truncated. A "Show more" button that reveals nothing is confusing.
  • Recheck on resize. Whether text is truncated depends on width. Use a ResizeObserver if your layout changes significantly between breakpoints.

A React Version

"use client";

import { useLayoutEffect, useRef, useState } from "react";

export function ClampedText({ text, lines = 3 }: { text: string; lines?: number }) {
  const ref = useRef<HTMLParagraphElement>(null);
  const [expanded, setExpanded] = useState(false);
  const [truncated, setTruncated] = useState(false);

  useLayoutEffect(() => {
    const el = ref.current;
    if (!el) return;
    const check = () => setTruncated(el.scrollHeight > el.clientHeight + 1);
    check();
    const observer = new ResizeObserver(check);
    observer.observe(el);
    return () => observer.disconnect();
  }, [text]);

  return (
    <div>
      <p ref={ref} className={expanded ? "" : "clamp"} style={{ ["--clamp-lines" as string]: lines }}>
        {text}
      </p>
      {(truncated || expanded) && (
        <button type="button" aria-expanded={expanded} onClick={() => setExpanded((v) => !v)}>
          {expanded ? "Show less" : "Show more"}
        </button>
      )}
    </div>
  );
}

When Not to Clamp Text

Clamping is a layout convenience, not a content strategy. Avoid it when:

  1. The hidden text is essential. Prices, legal disclaimers, error messages, and form instructions must never be clamped.
  2. There is no way to reach the full text. A clamped excerpt is fine if the card links to the full article. A clamped product description with no toggle is not.
  3. Users zoom or change text spacing. WCAG 1.4.4 requires that text can be resized to 200% without loss of content, and 1.4.12 requires content to survive increased spacing (line height 1.5, paragraph spacing 2×, letter spacing 0.12em, word spacing 0.16em). Line-based clamping adapts better than a fixed max-height, but it still hides more text as text grows, so make sure the full content is always reachable.
  4. Headlines carry meaning. Truncating a headline mid-phrase can change what it says. Consider editing headlines to a sensible length instead, and use text-wrap: balance so short ones look good.

If you are designing for small screens specifically, the post on readable typography for mobile screens covers the broader sizing and spacing decisions, and how to make website typography accessible covers the WCAG requirements in more depth.

Clamping vs. Truncating on the Server

Sometimes the better answer is to shorten text before it reaches the browser, for example a fixed-length excerpt generated from the article body. Compare the approaches:

ApproachProsCons
CSS line-clampAdapts to width and font size, no content changesFull text still downloaded, visual only
Server-side character limitSmaller HTML, predictable lengthDoes not adapt to layout, may cut mid-word
Editorial excerpt fieldBest wording, written for the contextRequires authors to write it

Many content sites use a combination: a frontmatter description or excerpt field as the source, and a CSS clamp as the safety net when the excerpt runs longer than the card allows.

line-clamp FAQ

Yes. Despite the prefix, it works in all current major browsers including Firefox, and the CSS Overflow specification documents it for web compatibility. Use it together with display set to -webkit-box, vertical box orientation, and hidden overflow.

Usually one of the required declarations is missing, the element has a display value from another rule overriding the -webkit-box value, or you are clamping a container with multiple block children instead of a single text element. Check the computed styles in DevTools to confirm all four declarations apply.

The clamped element has bottom padding, and overflow clipping happens at the padding edge, so the hidden line shows through. Move the padding to a wrapper element and keep the clamped element itself free of vertical padding.

Yes. Clamping hides text visually but leaves it in the accessibility tree, so screen readers announce the full content. That is usually desirable, but make sure sighted users can also reach the full text through a link or a show more button.

Not directly, because the number of lines is a discrete value. To animate expansion, transition max-height between a clamped height and a large value, or use a view transition. Keep the animation short and respect the reduced motion preference.

Compare the element's scrollHeight to its clientHeight. If scrollHeight is larger, content is hidden. Re-run the check when the element resizes, since truncation depends on the available width.

Conclusion

line-clamp is the cleanest way to keep cards, lists, and previews tidy when content length is unpredictable. The working recipe is four declarations: display: -webkit-box, -webkit-box-orient: vertical, -webkit-line-clamp, and overflow: hidden, with the unprefixed line-clamp added for the future. For a single line, use text-overflow: ellipsis and remember min-width: 0 in flex layouts.

The details are what separate a polished implementation from a buggy one. Keep padding off the clamped element, clamp a single text block, use consistent line heights, and add an accessible toggle whenever the full text is not available elsewhere. Never clamp content people need to complete a task.

Here are some useful references for going deeper on line clamping:

  1. MDN Web Docs: -webkit-line-clamp — syntax, required declarations, and browser compatibility.
  2. MDN Web Docs: text-overflow — single-line truncation with ellipsis.
  3. W3C: CSS Overflow Module Level 4 — the specification for line-clamp and its legacy prefixed form.
  4. Tailwind CSS: line-clamp — the built-in utilities in Tailwind v4.
  5. W3C WAI: Understanding SC 1.4.12 Text Spacing — why truncated text must survive increased spacing.
Share :

Related Posts

Ascenders, Descenders, and Baselines: The Anatomy of a Letterform

Ascenders, Descenders, and Baselines: The Anatomy of a Letterform

You align an icon next to a button label and it looks a pixel or two too high, no matter how you adjust vertical-align. You set overflow: hidden

Continue Reading
Are Google Fonts GDPR-Compliant?

Are Google Fonts GDPR-Compliant?

In late 2022, thousands of small business owners in Germany and Austria opened letters demanding a few hundred euros in "damages" because their websi

Continue Reading
How to Audit Web Font Performance with Lighthouse?

How to Audit Web Font Performance with Lighthouse?

A client sends you a screenshot of their PageSpeed Insights report: performance score 61, LCP 3.9 seconds, and a vague list of warnings. They want to

Continue Reading