prefer_text_rich
v0.4.0 Warning Fix Widget Replacement
Flags usages of RichText which should be replaced with Text.rich. RichText does not respect MediaQuery text scaling by default, which can break accessibility for users who configure larger text sizes.
Why use this rule
Section titled “Why use this rule”RichText is the raw widget: textScaler defaults to TextScaler.noScaling,
and it inherits nothing from DefaultTextStyle. Text written with it stays the
same size when the user raises the system font scale, and ignores whatever style
the surrounding theme set.
Text.rich is a thin wrapper that reads both from context. It is the same
InlineSpan tree, so the change is mechanical — the quick fix moves the text:
argument to the first positional slot and carries the rest.
See also: Text.rich | RichText
// A price line that does not grow with the user's text-size setting.RichText( text: TextSpan( text: 'Total: ', children: [ TextSpan(text: '42 USD', style: TextStyle(fontWeight: FontWeight.bold)), TextSpan(text: ' incl. VAT'), ], ),);Text.rich( TextSpan( text: 'Total: ', children: [ TextSpan(text: '42 USD', style: TextStyle(fontWeight: FontWeight.bold)), TextSpan(text: ' incl. VAT'), ], ),);Note what the rewrite also fixes: the un-styled spans now inherit the ambient
DefaultTextStyle, where under RichText they fell back to the framework
default.
Examples
Section titled “Examples”Other arguments carry across
Section titled “Other arguments carry across”textAlign, maxLines, overflow, softWrap, strutStyle and locale are
all named the same on both widgets:
// Don'tRichText( text: TextSpan(text: 'A very long line of body copy'), maxLines: 2, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center,);
// DoText.rich( TextSpan(text: 'A very long line of body copy'), maxLines: 2, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center,);Set the base style once
Section titled “Set the base style once”Because Text.rich inherits, the outer TextSpan usually stops needing a style
at all:
// Don't — every span has to name the style RichText will not supplyRichText( text: TextSpan( style: Theme.of(context).textTheme.bodyMedium, text: 'Read our ', children: [ TextSpan(text: 'terms', style: const TextStyle(decoration: TextDecoration.underline)), ], ),);
// Do — bodyMedium comes from the theme via DefaultTextStyleText.rich( TextSpan( text: 'Read our ', children: [ TextSpan(text: 'terms', style: const TextStyle(decoration: TextDecoration.underline)), ], ),);Known limitations
Section titled “Known limitations”textDirection behaves differently. RichText requires either an explicit
textDirection or an ambient Directionality. Text.rich always falls back to
Directionality, so an explicit argument the fix carries over is usually
redundant afterwards and can be deleted.
selectionRegistrar has no Text.rich equivalent. It exists only on
RichText; the fix will copy it and the result will not compile. Wrap a
Text.rich in a SelectionArea instead, or keep the RichText and silence the
line with // ignore: many_lints/prefer_text_rich.
textScaleFactor is deprecated on both. If the code you are converting
passes it, replace it with textScaler: at the same time.
Configuration
Section titled “Configuration”This rule is in the recommended preset, so it is on with
preset: recommended or preset: opinionated. Add it to preset: core with
prefer_text_rich: true.
To turn it off:
rules: prefer_text_rich: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Related rules
Section titled “Related rules”prefer_center_over_align— Use Center instead of Align when alignment is center.prefer_sized_box_square— Use SizedBox.square when width and height are equal.avoid_border_all— Use Border.fromBorderSide instead of Border.all for const support.avoid_expanded_as_spacer— Use Spacer instead of Expanded with an empty child.