🔠 Text scaling

Common mistake

A common mistake is ignoring the user’s system font size setting. Text is sized with hard-coded pixel values and no TextScaler is applied, so the layout looks identical regardless of the accessibility settings the user has configured. Users who need larger text cannot benefit from their own system preferences.

🎯 Relevant elements

This guideline applies to every widget that renders text:

  • Body text and labels (Text, RichText)
  • Button labels
  • Dialog and bottom sheet content
  • List item titles and subtitles
  • Any custom text widget that sets fontSize explicitly

WCAG Guideline

This guideline is based on WCAG 2.2 — 1.4.4 Resize Text (Level AA). Text must be resizable up to 200 percent without loss of content or functionality, except for captions and images of text.


Solution

Flutter’s Text widget respects the system text scale automatically through MediaQuery.textScalerOf(context). The main risk is suppressing that behaviour unintentionally.

✅ Respect the system text scale (default behaviour)

Do not pass a hard-coded textScaleFactor or textScaler to MediaQuery. Let Flutter resolve the scale from the system.

// ✅ Do - Text respects the system text scale automatically
Text(
  'Hello, world!',
  style: const TextStyle(fontSize: 16),
);

✅ Apply the scale explicitly when computing custom sizes

When you calculate a font size at runtime, apply the system scale manually so that the computed size also scales.

// ✅ Do - scale the computed font size with the system scaler
final fontSize = MediaQuery.textScalerOf(context).scale(16);

Text(
  'Hello, world!',
  style: TextStyle(fontSize: fontSize),
);

⚠️ Suppress scaling only on layout-critical components

Some components have strict layout constraints (e.g. a carousel item with a fixed tile height). In these cases, suppressing the text scale may be necessary to prevent overflow, but it should be treated as an accessibility trade-off and used sparingly.

// ⚠️ Only use when layout overflow cannot be solved any other way
MediaQuery(
  data: MediaQuery.of(context).copyWith(
    textScaler: TextScaler.linear(1.0), // fixed scale, ignores system setting
  ),
  child: Text(
    'Carousel title',
    style: const TextStyle(fontSize: 14),
  ),
);

Prefer solving overflow through layout instead:

// ✅ Prefer - allow the text to scale but clip gracefully
Text(
  carouselTitle,
  style: const TextStyle(fontSize: 14),
  maxLines: 2,
  overflow: TextOverflow.ellipsis,
);

Overflow strategies

When scaled text no longer fits its container, handle overflow explicitly rather than clipping or hiding content:

Strategy When to use
TextOverflow.ellipsis Short single-line labels where truncation is acceptable
maxLines: n Multi-line content with a maximum visible line count
Flexible/Expanded layout Containers that can grow to fit the text
Scrollable content Labels inside cards or tiles that may become long
// ✅ Do - ellipsis for fixed-size tiles
Text(
  artifactTitle,
  maxLines: 1,
  overflow: TextOverflow.ellipsis,
  style: const TextStyle(fontSize: 14),
);

Validation & Testing

🛠️ Work in progress…


🛠️ Usage baseflow-a11y-components library

🛠️ Work in progress…


This site uses Just the Docs, a documentation theme for Jekyll.