UIDex

Truncation (Ellipsis and Line Clamp)

قصّ النصّ

text-overflow: ellipsis

also calledellipsis، line clamp، text overflow، clamped text، shortened label، cut off text، اقتطاع النصّ، تقصير النصّ، النقاط الثلاث، حصر الأسطر، لاين كلامب، إليبسس

Truncation shows part of a string that does not fit its box, plus a mark that says there is more: the ellipsis character. The full string stays in the DOM, because the cut happens in the presentation layer, so Ctrl+F still finds it, a copy takes all of it, and a screen reader reads all of it. It comes in three shapes, and each needs a different technique: an end cut on one line with text-overflow, a limit of N lines with line-clamp, and a middle cut that keeps the start of the name together with its extension, which CSS has no property for. It is not a silent clip (overflow: hidden on its own), which slices a letter in half and leaves no mark, so the user never learns anything is missing. A server-side excerpt built with substring is a different thing again, because it drops the rest from the response and nothing in the browser can bring it back. Nor is it a collapsible "read more" block, a two-state control with a button between the states, where truncation is one display state that may have an expand button attached to it. One rule settles its use: the truncated text has to stay readable in full somewhere, or you are hiding information rather than shortening it.

If you called it…

"the title that gets cut with dots at the end""how do I stop the paragraph after two lines""the file name does not fit in the table cell""text spilling outside its box""hide the rest of the description behind a link"

Live specimen

Interact with the demo. Every part is real and numbered.

المرفقات

كشف-حساب-ال…-٢٠٢٦.xlsx

يسري هذا العرض حتى ١٢ سبتمبر ٢٠٢٦، ويشمل تصميم الصفحات وتنفيذها واختبارها على المتصفّحات المذكورة في الملحق. وأي طلب خارج النطاق المتّفق عليه يُسعَّر على حدة بعد موافقة كتابية منك.

RTLالنقاط تقع عند نهاية السطر المنطقية، أي عند الحافّة اليسرى في العربية

Anatomy: every part, named

Hover a row to locate it in the demo above.

Build prompt

Implement text truncation in this interface in all three of its forms. For a single line, put text-overflow: ellipsis, overflow: hidden, and white-space: nowrap on the same element, add min-inline-size: 0 to any flex or grid child so it can shrink and the dots can appear, and set table-layout: fixed on any table whose cells you truncate. For multiple lines, use -webkit-line-clamp together with display: -webkit-box, -webkit-box-orient: vertical, and overflow: hidden, and set line-height to at least 1.7 in Arabic paragraphs so descenders on the last line are not shaved off. For a middle cut, nothing in CSS does it, so write it in JavaScript with Intl.Segmenter at grapheme granularity, keep the head of the name and its extension, and derive the character count from the element width measured with a ResizeObserver instead of a constant. Guarantee full access to the text in every case: a tooltip on a focusable trigger that opens on hover and on focus and is tied to it with aria-describedby, or an expand <button> with aria-expanded and aria-controls that stays visible afterwards as "Show less". Do not rely on the title attribute, which keyboard users cannot open and touch never shows. Never truncate a price, a deadline, or a rejection reason unless it is written in full somewhere else on the screen. Use logical properties for every space and position: padding-inline-end, margin-inline, inset-inline-start, and never padding-right or left. If you replace the dots with a fade, add an explicit rule under [dir="rtl"] that flips the linear-gradient direction. Wrap Latin file names in <bdi> so bidi reordering stops at their edges, and put dir="auto" on any box whose text direction you do not know in advance.

How it behaves right-to-left

This section is ours alone.

Which edge gets cut

mirrors

The cut lands at the logical end of the line, which is the left edge in Arabic, and text-overflow gets that right on its own with no extra rule from you. What breaks it is direction: ltr on the container, usually added to tidy up numbers or file names: the end of the line moves to the right, so the ellipsis eats the opening of the Arabic sentence and keeps its tail. When the value can arrive in either direction, put dir="auto" or unicode-bidi: plaintext on the truncating element itself. A <bdi> around the value is not enough here, since it isolates the ordering without moving the dots: the edge that gets cut follows the direction of the block.

The fade mask

mirrors

Some designs replace the dots with a gradient fade at the edge, and that does not mirror by itself, because gradients accept no logical keyword: linear-gradient takes to right and to left, and there is no to inline-end. A mask written as to right stays on the right in Arabic while the cut happens on the left, so you get a fade over intact text and a chopped letter with nothing softening it. Redeclare the gradient with to left under [dir="rtl"], and do the same for mask-image. Reserve the space with padding-inline-end, since a hard-coded padding-right leaves the gap at the wrong edge.

A middle cut counts in logical order

never mirrors

A JavaScript string is always stored in logical order: its first item is the first character you read, in Arabic exactly as in English. Build the middle cut straight on that order, and do not try to "fix" it by reversing the string or by going off what you see on screen, because the visual arrangement is produced by the bidi algorithm at paint time and is not how the text is stored. The real trap is that the split point can land inside a single grapheme cluster, detaching a shadda or a fatha from its letter and leaving it hanging on the ellipsis. Segment with Intl.Segmenter at grapheme granularity before you cut.

A Latin name inside an Arabic line

never mirrors

text-overflow removes whatever sits at the visual end of the line after the bidi algorithm has reordered it, and the visual end is not necessarily the logical end of the string. Put a Latin file name such as Q4-report-final.pdf at the end of an Arabic sentence and let the line overflow: the cut starts at the first letters of the name, because a Latin run is laid out left to right while the line ends on the left. You keep the extension and lose the part that told two files apart. Wrap the name in <bdi>, which isolates it and carries dir="auto", so its order resolves inside its own boundaries and neighbouring punctuation stops migrating across it, and when the head of the name is what matters, cut in the middle in JavaScript instead of leaving it to text-overflow.

Line height in a clamped paragraph

never mirrors

A clamp cuts everything past a height derived from line-height, and Arabic letters drop further below the baseline than Latin ones: the tails of jeem, hah and yeh, and the dots underneath them. With the line-height: 1.2 that is common in English paragraphs, overflow: hidden shaves the bottom off the last visible line and the text looks chopped. Start at line-height: 1.7 or 1.8 for an Arabic paragraph, and remember the total height grows by the same factor, so you may need two lines where English had three to keep the card the same height.

In code

Each row is one framework's word for the same thing. Take the row your project speaks.

CSStext-overflow: ellipsisOne line only, and dead unless overflow: hidden and white-space: nowrap sit on the same element.
CSS-webkit-line-clamp: 2The multi-line clamp; the unprefixed line-clamp is specified in CSS Overflow 4 and is landing, so check support before dropping the prefixed lines.
CSSmin-inline-size: 0What lets a flex child shrink below its content width; without it the dots never show.
HTML<bdi>Isolates a Latin name inside an Arabic line and carries dir="auto", so bidi reordering stops at its edges.
ARIAaria-expanded + aria-controlsThe pair that makes a "show more" button legible to a screen reader and ties it to the paragraph it opens.
Ant Design<Typography.Paragraph ellipsis={{ rows: 2, expandable: true }} />Gives you the clamp, the expand control, and the tooltip in one option, and takes a suffix to keep an extension visible.
SwiftUI.truncationMode(.middle)Apple ships the middle cut alongside .lineLimit, which is exactly what CSS does not have.

See also

Updated · 2026-08-19