Type something to search...
How to truncate text with CSS ellipsis and line clamping?

How to truncate text with CSS ellipsis and line clamping?

To truncate text with CSS, use two different techniques depending on how many lines you want to keep. For a single line, combine overflow: hidden, white-space: nowrap and text-overflow: ellipsis on an element with a constrained width, and the browser will cut the text and add "…" at the end. For several lines, use line clamping: set display: -webkit-box, -webkit-box-orient: vertical, -webkit-line-clamp to the number of lines and overflow: hidden. Despite the prefixes, the line-clamp pattern works in every current major browser. Both techniques only hide text visually, so the full content stays in the page for search engines, copy and paste and screen readers.

Truncation keeps cards, tables, menus and lists tidy when content length is unpredictable, such as user names, product titles or article excerpts. Done badly, it hides important information or fails silently because a parent layout overrides it. In this article you'll learn the single-line recipe and why each property is needed, how multi-line clamping works, how to fix truncation inside flexbox, grid and tables, how to truncate in the middle of a string, and how to make truncated text accessible.

Single-Line Truncation with text-overflow

The classic single-line pattern needs four things:

.truncate {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
<p class="truncate" style="max-width: 18rem">
  Quarterly planning notes for the design systems working group
</p>
Quarterly planning notes for the de…

Each line of the recipe does a specific job:

  • overflow: hidden: clips content that extends beyond the box. text-overflow only takes effect when overflow is something other than visible.
  • white-space: nowrap: stops the text wrapping onto a second line, so it overflows horizontally instead.
  • text-overflow: ellipsis: replaces the clipped part with an ellipsis character.
  • A constrained width: the element must be narrower than its content. Block elements get this from their container; inline elements need display: block or inline-block plus a width or max-width.

Truncating Inline Elements

text-overflow applies to block containers, so it won't work on a plain span or a. Give the element a block-level display and a size:

.username {
  display: inline-block;
  max-width: 12ch;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  vertical-align: bottom;
}

The vertical-align: bottom fixes a small baseline gap that can appear because inline-block elements with overflow: hidden align their bottom edge to the baseline.

Custom Overflow Strings

The specification also allows a custom string, such as text-overflow: " [...]", but only Firefox supports it. Stick with ellipsis for anything cross-browser.

Multi-Line Truncation with line-clamp

When you want two or three lines followed by an ellipsis, such as an article excerpt on a card, use line clamping:

.excerpt {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
}
<p class="excerpt">
  A practical walkthrough of how our team rebuilt the onboarding flow,
  what we measured before and after, which changes made the biggest
  difference, and the mistakes we'd avoid if we had to do it again.
</p>
A practical walkthrough of how our team
rebuilt the onboarding flow, what we
measured before and after, which…

This pattern originated in WebKit and uses an old flexbox syntax, but it has been standardised in practice. All current versions of Chrome, Edge, Firefox and Safari support it. The CSS Overflow Module Level 4 specification also defines an unprefixed line-clamp property, but browser support for the unprefixed version is still limited, so the prefixed form is the one to use. You can include both:

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

Things That Break line-clamp

Line clamping is sensitive to a few properties:

  • Changing display: if another rule sets display: block or flex, the clamp stops working. The -webkit-box display is required.
  • Padding at the bottom: vertical padding sits inside the clipped area, so part of the fourth line may peek through. Put padding on a wrapper instead.
  • Multiple child elements: clamping works on the line boxes inside the element. If the element contains several block children, such as multiple paragraphs, the result can be unpredictable. Clamp a single block of text.
  • Missing overflow: hidden: without it, the ellipsis appears but the extra lines still show.

Responsive Line Counts

You can change the number of lines at different widths, or drive it from a custom property:

.card__excerpt {
  --lines: 2;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: var(--lines);
  overflow: hidden;
}

@media (min-width: 48em) {
  .card__excerpt {
    --lines: 4;
  }
}

Fixing Truncation in Flexbox and Grid

A very common complaint is "my ellipsis works on its own but not inside a flex row". The cause is the minimum size of flex and grid items. By default, a flex item has min-width: auto, which means it won't shrink below the width of its content. Since the content is one long unwrapped line, the item refuses to shrink, and there's nothing to truncate.

Here's a typical list row with an icon, a title and a date:

<li class="row">
  <img class="row__icon" src="/icons/file.svg" alt="" width="20" height="20">
  <span class="row__title">Annual-report-final-v3-approved-by-finance-team.pdf</span>
  <time class="row__date" datetime="2026-09-14">14 Sep</time>
</li>
.row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.row__title {
  flex: 1;
  min-width: 0;              /* allow the item to shrink */
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.row__icon,
.row__date {
  flex-shrink: 0;            /* keep these at their natural size */
}

min-width: 0 is the critical line. If the truncating element is nested deeper, the flex item that contains it needs min-width: 0 too.

Grid has the same behaviour. A track sized 1fr has an automatic minimum, so use minmax(0, 1fr):

.layout {
  display: grid;
  grid-template-columns: 16rem minmax(0, 1fr);
}

Truncating Text in Tables

Table cells expand to fit their content by default, so ellipsis doesn't work in a normal table. Switch the table to a fixed layout and give columns explicit widths:

.files {
  width: 100%;
  table-layout: fixed;
  border-collapse: collapse;
}

.files th:nth-child(1) { width: 60%; }
.files th:nth-child(2) { width: 20%; }
.files th:nth-child(3) { width: 20%; }

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

With table-layout: fixed, column widths come from the first row and the table's width, not from cell content, so long text truncates instead of stretching the column.

Truncating in the Middle

CSS can only truncate at the end of a line (or at the start, for right-to-left text). For file names, email addresses or URLs, the end is often the most useful part: invoice-2026-09-… hides the extension. Truncating in the middle keeps both ends visible.

A small JavaScript function handles this for strings of known length:

function truncateMiddle(text, maxLength) {
  if (text.length <= maxLength) return text;
  const keep = maxLength - 1;          // leave room for the ellipsis
  const start = Math.ceil(keep / 2);
  const end = Math.floor(keep / 2);
  return `${text.slice(0, start)}…${text.slice(-end)}`;
}

console.log(truncateMiddle("annual-report-final-v3-approved.pdf", 20));
annual-rep…roved.pdf

A CSS-only alternative splits the string into two spans, truncates the first with ellipsis and keeps the second at its natural width:

<span class="mid-trunc" title="annual-report-final-v3-approved.pdf">
  <span class="mid-trunc__start">annual-report-final-v3-appro</span><span class="mid-trunc__end">ved.pdf</span>
</span>
.mid-trunc {
  display: flex;
  min-width: 0;
  white-space: nowrap;
}

.mid-trunc__start {
  overflow: hidden;
  text-overflow: ellipsis;
}

.mid-trunc__end {
  flex-shrink: 0;
}

Accessibility and Usability

Truncation is a visual change, so it has a few side effects to manage.

Screen Readers and Search Engines

Text hidden by overflow is still in the DOM. Screen readers read the full string, search engines index it and users can copy it. That's generally good. Avoid truncating with JavaScript by actually removing characters from the DOM unless you also expose the full text, for example with an aria-label on a link or a visually hidden span.

Revealing the Full Text

Sighted users can't see what's hidden, so give them a way to get it:

  • A title attribute: shows a tooltip on hover. It's quick to add, but it doesn't appear on touch devices or for keyboard users, so treat it as a bonus rather than the only route.
  • A link to the full content: for excerpts, the card usually links to the article anyway.
  • A "Show more" toggle: remove the clamp on click.

Here's a minimal accessible toggle:

<div class="review">
  <p id="review-1" class="review__text is-clamped">
    The delivery arrived a day early and the packaging was excellent...
  </p>
  <button type="button" aria-controls="review-1" aria-expanded="false">Show more</button>
</div>
.is-clamped {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
}
document.querySelectorAll(".review button").forEach((button) => {
  const text = document.getElementById(button.getAttribute("aria-controls"));
  button.addEventListener("click", () => {
    const expanded = button.getAttribute("aria-expanded") === "true";
    text.classList.toggle("is-clamped", expanded);
    button.setAttribute("aria-expanded", String(!expanded));
    button.textContent = expanded ? "Show more" : "Show less";
  });
});

Text Zoom and Spacing

WCAG 2.2 Success Criterion 1.4.12 (Text Spacing) requires that content still works when users increase line height, letter spacing and word spacing. Users who enlarge text will see less of a truncated string, so don't truncate anything essential, such as error messages, prices or form labels. If a value must be readable in full, let it wrap.

Detecting Whether Text Was Truncated

To show a toggle or tooltip only when needed, compare the element's scroll size to its visible size:

function isTruncated(el) {
  return el.scrollWidth > el.clientWidth || el.scrollHeight > el.clientHeight;
}

document.querySelectorAll(".truncate, .excerpt").forEach((el) => {
  if (isTruncated(el)) {
    el.title = el.textContent.trim();
  }
});

Run it after fonts have loaded, for example inside document.fonts.ready.then(), because a font swap changes text width.

A Reusable Utility Set

Most projects only need two utilities. Here they are together:

.u-truncate {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  min-width: 0;
}

.u-clamp {
  --lines: 2;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: var(--lines);
  line-clamp: var(--lines);
  overflow: hidden;
}

.u-clamp-3 { --lines: 3; }
.u-clamp-4 { --lines: 4; }

If you use Tailwind CSS, the built-in truncate and line-clamp-* utilities generate the same declarations.


FAQ: Truncating Text with CSS

Usually one of the required properties is missing: overflow must be hidden, white-space must be nowrap, and the element must be a block or inline-block with a constrained width. Inside flexbox, the item also needs min-width set to 0.

Yes. Use display set to -webkit-box, -webkit-box-orient set to vertical, -webkit-line-clamp set to the number of lines, and overflow set to hidden. It works in all current major browsers.

Yes. Despite the prefix, it's supported in Chrome, Edge, Firefox and Safari. The unprefixed line-clamp property has limited support so far, so keep the prefixed version and add the unprefixed one alongside it if you like.

Yes. CSS truncation only hides text visually, so screen readers announce the full content. That's another reason to truncate with CSS rather than cutting the string in JavaScript.

CSS only truncates at the end of a line. Use a short JavaScript function to keep the start and end of the string, or split the text into two spans and truncate only the first one.

No. The full text remains in the HTML, so search engines can still read and index it. Only the visual display is shortened.


Conclusion

CSS gives you two reliable truncation tools. For a single line, overflow: hidden, white-space: nowrap and text-overflow: ellipsis on a width-constrained block do the job. For several lines, the -webkit-line-clamp pattern works in every current browser and is easy to make responsive with a custom property. Most failures come from layout context, so remember min-width: 0 in flexbox, minmax(0, 1fr) in grid and table-layout: fixed in tables.

Use truncation for content where the gist is enough, such as titles, file names and excerpts, and never for information users must read in full. Give people a way to see the whole text through a link, toggle or tooltip, and keep the full string in the DOM so assistive technology and search engines still get it. With those rules, truncation keeps your layouts tidy without hiding anything that matters.

Share :

Related Posts

How to make typography accessible?

How to make typography accessible?

You make typography accessible by choosing clear typefaces, setting text in relative units so it scales with user preferences, giving it enough colou

Dive Deeper
What are the parts of a letterform?

What are the parts of a letterform?

A letterform is the shape of a single letter, and typographers break it down into named parts. The main ones are the stem (the main vertical

Dive Deeper
What are ascenders, descenders and the baseline?

What are ascenders, descenders and the baseline?

The baseline is the invisible line that letters sit on. Ascenders are the parts of lowercase letters that rise above the x-height, such as th

Dive Deeper