Text topic

Texts and fields support every Unicode writing system. Arabic and English are examples alongside Hebrew, Persian, Urdu, Cyrillic, Greek, Indic, CJK and supplementary-plane scripts. Font coverage remains the host application's job.

How the direction is chosen

The first strong Unicode Bidi_Class character (L, R or AL) decides. The data is pinned to Unicode 17.0.0, with no language allowlist. This detects direction, not the language of a sentence.

  • Weak/neutral characters do not decide: ،Hello is LTR and 。שלום is RTL.
  • Combining marks and emoji are skipped; isolated content does not decide the outer direction. Some punctuation, such as Arabic ؟, is strong in Unicode and retains its assigned direction.
  • Mixed text follows its first strong character; an explicit direction wins.
  • Without a strong character, widgets keep ambient direction; pure helpers use their explicit fallback (LTR by default).
  • Only the first 256 UTF-16 code units are read, decoding complete pairs only. Letters beyond the cap are ignored. This is a bounded paragraph-direction heuristic; Flutter handles visual bidirectional layout.
final arabic = detectTextDirection('مرحبا بالعالم'); // rtl
final english = detectTextDirection('Hello'); // ltr
final mixed = detectTextDirection('123 مرحبا'); // rtl, digits are skipped
final symbols = detectTextDirection('(#1) مرحبا'); // rtl, symbols are skipped
final none = detectTextDirection('12345', fallback: TextDirection.rtl); // rtl

Show text in its own direction

MREAutoText takes every parameter of Text: style, lines, overflow, scaling and the rest. Set textDirection to turn detection off.

final column = Column(
  crossAxisAlignment: CrossAxisAlignment.stretch,
  children: const [
    MREAutoText('مرحبا بالعالم'), // reads right to left
    MREAutoText('Hello world'), // reads left to right
    MREAutoText('مرحبا', textDirection: TextDirection.ltr), // fixed
  ],
);

Style it like any Text

final text = MREAutoText(
  'مرحبا بالعالم',
  style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
  maxLines: 1,
  overflow: TextOverflow.ellipsis,
  autoAlign: true, // pins the text to the side its content starts on
);

autoAlign pins the text to the side its content starts on. Without it, TextAlign.start already follows the detected direction.

Use it on a Text you already have

autoDirection() and autoAlign() copy the Text with every property kept. A value you set yourself is never replaced.

final text = Text(
  name,
  style: const TextStyle(fontSize: 20),
).autoDirection().autoAlign();

Get the direction or the alignment of a string

final isRtl = 'مرحبا'.isRtl; // true
final direction = '12345'.directionOr(TextDirection.rtl); // rtl
final arabic = 'مرحبا'.autoTextAlign; // TextAlign.right
final english = 'Hello'.autoTextAlign; // TextAlign.left
final digits = '12345'.autoTextAlign; // TextAlign.start

Flip any widget

withTextDirection adds a Directionality only when the direction differs from the surrounding one.

final tile = ListTile(
  leading: const Icon(Icons.person),
  title: Text(name),
).withTextDirection(name);

Remove broken characters

Some keyboards and pastes produce unpaired surrogates. Flutter throws on them when it lays out the text. safeDisplayText replaces each one with U+FFFD and keeps valid pairs such as emoji.

final label = Text(safeDisplayText(pasted));

Classes

MREAutoText Text
A Text whose direction follows its content.

Extensions

MREAutoDirectionText on Text Text
Direction and alignment from content, on an existing Text.
MREDirectionalWidget on Widget Text
Gives a widget the direction of a sample text.
MRETextDirection on String Text
Direction checks on String.

Functions

detectStrongTextDirection(String text) → TextDirection? Text
Returns the direction of the first strongly directional character in text, or null when there is none.
detectTextDirection(String text, {TextDirection fallback = TextDirection.ltr}) → TextDirection Text
Returns the direction of the first strongly directional character in text.
safeDisplayText(String text) → String Text
Returns text without unpaired UTF-16 surrogates.