Skip to content

feat(lint): add text_truncated check for content clipped by overflow-hidden containers - #2767

Closed
xuanruli wants to merge 2 commits into
mainfrom
xuanru/text-truncated-check
Closed

feat(lint): add text_truncated check for content clipped by overflow-hidden containers#2767
xuanruli wants to merge 2 commits into
mainfrom
xuanru/text-truncated-check

Conversation

@xuanruli

@xuanruli xuanruli commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

The gap

The layout audit's overflow detectors compare bounding boxes: overflowFor(subject, container, …) fires only when a subject's bbox extends beyond its container's. But when text is clipped by an overflow:hidden ancestor (with or without text-overflow:ellipsis), getBoundingClientRect returns the already-clipped box, constrained to the container. The bbox comparison sees no spill, so the lost content is invisible to every existing check — no scrollWidth/clientWidth-based truncation detection existed.

The fix

A new browser-side detector (textTruncationIssues in layout-audit.browser.js) flags text-bearing elements where scrollWidth > clientWidth (horizontal) or scrollHeight > clientHeight (vertical) and a clipping element — the element itself or an ancestor below the composition root — actually hides that overflow (clipsOverflow). It:

  • reports the innermost truncated box per nesting chain (a clipping container and the text child that overflows it both trip the check; only the child is reported)
  • defers self-clipping elements that own their text to the existing clipped_text check (no double-report)
  • respects data-layout-allow-overflow/data-layout-bleed and adds an explicit data-layout-allow-truncation opt-out
  • emits text_truncated at warning severity (matches the text_box_overflow posture — a clipped label is a real defect but not render-breaking), with a snippet, selector, container selector and fix hint

Wired through the same path as the sibling layout findings: browser detector → checkBrowser.ts parser allowlist → LayoutIssueCode union + persistence tiering in layoutAudit.tscheckPipeline.

Eval

Ran the built CLI (check <sample> --json) against the 4 rendered discovery samples the current check misses, plus clean controls:

Sample Defect text_truncated fires?
w3/fuzz000 concept-hub node labels ("Microgrid Active", "Vertical Farming", "100% Recycled") ✅ 3 findings on div.satellite-val (content width 144px > visible 126px)
w6/fuzz007 gantt bar status labels ("ACTIVE IN-PROGRE…", "Full Thrust Burn…") ✅ 4 findings on .task-bar (content width 418px > visible 346px)
w3/fuzz007 matrix quadrant/axis labels clipped vertically ✅ 4 findings on div.quad-title (content height 35px > visible 31px) — vertical truncation
w2/fuzz008 kanban DONE column, bottom card clipped ❌ not fired — see note

3 of 4 fire, and vertical truncation is covered (w3/fuzz007). The kanban miss is honest: its DONE column has no overflow:hidden and no height cap — it grows and its bottom card is cut by the canvas root edge. That is a bbox-extends-past-canvas defect (canvas_overflow's mechanism), not scrollWidth > clientWidth content-box truncation; no element there has content overflowing its own clipped box. Forcing it would duplicate canvas_overflow and risk false positives, so it is intentionally out of scope for this check.

Clean controls — no false positives: w1/fuzz003, w5/fuzz000, w5/fuzz002 all report text_truncated: 0.

Tests

Added to layout-audit.browser.test.ts: positive horizontal + vertical truncation under a clipping ancestor, negatives for text that fits and for overflow into a non-clipping container (visible, not lost), a no-double-report guard vs clipped_text, and opt-out guards for data-layout-allow-truncation and data-layout-allow-overflow. Full file: 78 tests pass; tsc --noEmit clean.

🤖 Generated with Claude Code

…hidden containers

The bbox-based overflow detectors miss text truncated by an overflow:hidden
ancestor — getBoundingClientRect returns the already-clipped box, so the bbox
comparison sees no spill and the lost content is invisible. scrollWidth >
clientWidth (or scrollHeight > clientHeight) exposes it: the content box is
larger than the visible box and a clipping element hides the difference.

Adds a browser-side detector (textTruncationIssues) that flags text-bearing
elements whose content overflows their box while a clipping element (self or an
ancestor below the composition root) swallows the overflow. Reports the
innermost box per nesting chain, respects data-layout-allow-overflow and a new
data-layout-allow-truncation opt-out, and defers self-clipping own-text to the
existing clipped_text check. Wired through the union type, parser allowlist and
persistence tiering as a warning.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@xuanruli
xuanruli marked this pull request as draft July 25, 2026 08:37
@xuanruli xuanruli closed this Jul 25, 2026
@xuanruli
xuanruli deleted the xuanru/text-truncated-check branch July 25, 2026 08:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant