🔠 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
TextScaleris 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
fontSizeexplicitly
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…