Text Spacing Override Testing for 1.4.12

Permalink to "Text Spacing Override Testing for 1.4.12"

Users with dyslexia and low vision often increase line height, letter spacing and word spacing with browser extensions or user stylesheets. WCAG 1.4.12 requires that content does not lose information or functionality when they do. Data grids are among the most fragile components here: fixed row heights clip the second line, overflow: hidden cuts off longer words, badges overflow their pills and column headers overlap sort icons. The criterion is easy to test automatically.

This guide belongs to visual regression & theme testing.

Spec reference

Permalink to "Spec reference"

SC 1.4.12 Text Spacing (AA) — no loss of content or functionality occurs when users set:

  • line height to at least 1.5 times the font size;
  • spacing after paragraphs to at least 2 times the font size;
  • letter spacing to at least 0.12 times the font size;
  • word spacing to at least 0.16 times the font size.

Content does not need to look good, but nothing may be cut off, overlap so it cannot be read, or become unusable.

Fixed-height cells versus flexible cells under text spacing Comparison: fixed row heights and overflow hidden clip text when spacing increases; min-height rows and wrapping keep everything readable. Fixed-height cells versus flexible cells under text spacing✗ Fixed-height cellsheight: 32px on rowsoverflow: hidden on textSecond line cut offHeader text overlaps sort iconBadge text spills out of pill✓ Flexible cellsmin-height: 32pxWrap or reveal on focusRow growsHeader wraps; icon stays alignedPill grows with its text

When to use — and when not to

Permalink to "When to use — and when not to"

Run text spacing tests on every component with constrained text: grid cells and headers, badges, chips, buttons, tabs, tooltips, KPI cards. Combine with 200% zoom for the strictest case.

Do not “pass” 1.4.12 by ignoring user styles (for example, !important on line-height in components). That blocks the very adjustments the criterion protects. Truncation with an ellipsis is acceptable only if the full text remains available (tooltip on focus, expandable row); clipping without access is a failure.

The misapplication: a compact grid with height: 28px; overflow: hidden on every cell, which clips descenders even before overrides are applied.

Running a text spacing test Flow: load the page, inject the spacing stylesheet, wait for layout, scan text containers for clipping, capture screenshots, then repeat at 200% zoom. Running a text spacing testLoad pagecomponent or full pagestable dataInject overridesline-height 1.5; letter 0.12em; word 0.16em; paragraph 2em!important user stylesScan for clippingscrollHeight > clientHeight with overflow hiddenreport elementsScreenshotdense componentsreview overlapsRepeat at 200% zoomcombined stressstrictest case

Annotated code example

Permalink to "Annotated code example"
// text-spacing.spec.js
const SPACING = `* { line-height: 1.5 !important; letter-spacing: 0.12em !important; word-spacing: 0.16em !important; }
                 p { margin-bottom: 2em !important; }`;

test('grid survives text spacing overrides (SC 1.4.12)', async ({ page }) => {
  await page.goto('/invoices');
  await page.addStyleTag({ content: SPACING });
  await page.waitForTimeout(100);                                   // allow layout
  const clipped = await page.evaluate(() => [...document.querySelectorAll('td, th, .badge, button, [role="tab"]')]
    .filter(el => {
      const cs = getComputedStyle(el);
      const hides = ['hidden', 'clip'].includes(cs.overflowY) || ['hidden', 'clip'].includes(cs.overflowX);
      const truncatedOk = cs.textOverflow === 'ellipsis' && el.hasAttribute('data-full-text');  // full text available
      return hides && !truncatedOk && (el.scrollHeight > el.clientHeight + 1 || el.scrollWidth > el.clientWidth + 1);
    })
    .map(el => el.textContent.trim().slice(0, 40)));
  expect(clipped).toEqual([]);
  await expect(page.getByRole('table', { name: 'Invoices' })).toHaveScreenshot('invoices-text-spacing.png');
});
/* Fixes that make the test pass */
.grid td, .grid th { min-block-size: 2rem; block-size: auto; overflow: visible; }   /* rows grow */
.badge { display: inline-flex; padding-block: .125em; line-height: inherit; }         /* pill grows */
.grid th .sort-icon { flex: none; }                                                   /* icon keeps its space */

Keyboard & AT behaviour

Permalink to "Keyboard & AT behaviour"

Text spacing does not change semantics, but clipped content often hides interactive elements:

Failure under overrides User impact Fix
Row action button pushed outside a fixed-height row Button unreachable visually; focus ring clipped Rows grow; overflow visible
Sort icon overlapping header text Header unreadable Flex layout with wrapping
Badge text clipped Status unreadable Pill grows with text
Tab labels overlapping Tabs unreadable Allow wrapping or scrolling tablist
Clipped elements found per component before fixes Bar chart of clipped elements detected by the text spacing test: data grid cells 38, column headers 9, badges 14, tabs 3 and buttons 2. Clipped elements found per component before fixesGrid cellsfixed row heightsColumn headersicons overlap textBadgesfixed pill heightTabsnowrap labelsButtonsfixed width
Grids and badges account for most failures.

Integration context

Permalink to "Integration context"

Text spacing interacts with density settings — see segmented controls for view density. Truncation must keep full text available, as in accessible tooltips for truncated cell text. Zoom testing is covered in zoom and reflow testing at 400 percent.

Gotchas

Permalink to "Gotchas"

Virtualized grids with fixed row heights. Many virtualizers require a fixed row height for performance. Use dynamic measurement (most libraries support it) or reserve enough height for 1.5 line height with two lines.

Canvas grids. Text drawn on canvas ignores user styles entirely, so 1.4.12 overrides have no effect — which also means users cannot adjust spacing at all. Canvas grids need their own spacing settings.

Icons sized in em. Icons that grow with letter spacing can push layouts; size icons in rem or px within flexible containers.

Common mistakes

Permalink to "Common mistakes"
  • Fixed row and pill heights.
  • !important line-height in components, blocking user styles.
  • Clipping without a way to reach full text.
  • Testing only the default density.

Framework notes

Permalink to "Framework notes"

AG Grid supports getRowHeight and auto-height rows (autoHeight: true on columns) — enable them, or test that fixed heights accommodate the overrides. MUI X has getRowHeight={() => 'auto'}. TanStack Virtual supports dynamic measurement with measureElement. In Storybook, a decorator can inject the spacing stylesheet for a “Text spacing” story variant.

// AG Grid: rows grow with their content
const columnDefs = [{ field: 'customer', wrapText: true, autoHeight: true }];

Worked example

Permalink to "Worked example"

An admin grid used 28-pixel fixed rows and pill badges with fixed height. The spacing test flagged 52 clipped elements on one page. Switching rows to minimum heights with auto growth, making badges inline-flex with padding, and letting headers wrap reduced the count to zero. The compact density still works by default; it simply grows when users need more space.

Testing checklist

Permalink to "Testing checklist"

Design system notes

Permalink to "Design system notes"

Ban fixed heights on text containers in component styles (lint for height: on cells, badges and buttons), and add a text-spacing story variant to every component. Make 1.4.12 part of component review.

FAQ

Permalink to "FAQ"
Does truncation with an ellipsis fail 1.4.12?

Not if the full text is available another way, such as a focus tooltip or an expandable row. Silent clipping fails.

Do I need to look good under overrides?

No — only avoid loss of content or functionality. Layouts can look looser.

Should components resist user styles?

No. Avoid !important on typography in component CSS; let user styles apply.

How do I test canvas-rendered grids?

Overrides do not reach canvas text. Offer in-app spacing settings and test those.

Is a bookmarklet enough for manual checks?

For spot checks, yes. Automate the same stylesheet in tests for regression coverage.

Does 1.4.12 apply to placeholder text and labels inside inputs?

Yes. Inputs need enough height for increased line height; fixed-height inputs often clip labels.

Which elements should the clipping scan include?

Any element that contains text and might constrain it: cells, headers, badges, chips, buttons, tabs, tooltips and inputs. Start broad and exclude known-safe containers as you learn your codebase.

Permalink to "Related"

← Back to Visual Regression & Theme Testing