Skip to content

RichText with WidgetSpan in RTL layout will be misplaced  #111381

Closed

Description

@jidasheng

The result is shown in the image:
image

The reproduction code is as follows:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(primarySwatch: Colors.blue),
        home: const MyHomePage());
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Directionality(
        textDirection: TextDirection.rtl,
        child: Scaffold(
            body: Center(
                child: RichText(
                    text: TextSpan(
          style: TextStyle(
              backgroundColor: Colors.black.withOpacity(0.5), fontSize: 30),
          children: [
            WidgetSpan(
                child: Container(color: Colors.red, width: 20, height: 20)),
            const TextSpan(text: '1-AQWER'),
            WidgetSpan(
                child: Container(color: Colors.green, width: 50, height: 20)),
            const TextSpan(text: '2-BNMVC')
          ],
        )))));
  }
}

I tested it on macos, ios and android. The problem can even be reproduced online at https://dartpad.dev/.

Activity

  1. added
    in triagePresently being triaged by the triage team
    on Sep 12, 2022
  2. exaby73 commented on Sep 12, 2022

    @exaby73
    Member

    Triage report

    I can reproduce this issue. This specific text and others like it seem to trigger this bug. Basically, have a - as the second character and this bug would be reproducible.

    Info

    Screenshot

    issue_111381_zl3K5BBEST

    Code Sample
    import 'package:flutter/material.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
            title: 'Flutter Demo',
            theme: ThemeData(primarySwatch: Colors.blue),
            home: const MyHomePage());
      }
    }
    
    class MyHomePage extends StatelessWidget {
      const MyHomePage({super.key});
    
      @override
      Widget build(BuildContext context) {
        return Directionality(
          textDirection: TextDirection.rtl,
          child: Scaffold(
            body: Center(
              child: RichText(
                text: TextSpan(
                  style: TextStyle(
                    backgroundColor: Colors.black.withOpacity(0.5),
                    fontSize: 30,
                  ),
                  children: [
                    WidgetSpan(
                      child: Container(
                        color: Colors.red,
                        width: 20,
                        height: 20,
                      ),
                    ),
                    const TextSpan(text: '1-ABCABC'),
                    WidgetSpan(
                      child: Container(
                        color: Colors.green,
                        width: 50,
                        height: 20,
                      ),
                    ),
                    const TextSpan(text: '2-DEFDEF')
                  ],
                ),
              ),
            ),
          ),
        );
      }
    }

    Flutter Doctor

    flutter doctor -v (Stable)
    [✓] Flutter (Channel stable, 3.3.1, on Microsoft Windows [Version 10.0.22000.918], locale en-US)
        • Flutter version 3.3.1 on channel stable at C:\Users\Nabeel\fvm\versions\stable
        • Upstream repository https://github.com/flutter/flutter.git
        • Framework revision 4f9d92fbbd (5 days ago), 2022-09-06 17:54:53 -0700
        • Engine revision 3efdf03e73
        • Dart version 2.18.0
        • DevTools version 2.15.0
    
    [✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
        • Android SDK at C:\android-sdk
        • Platform android-33, build-tools 33.0.0
        • Java binary at: C:\Program Files\Android\Android Studio\jre\bin\java
        • Java version OpenJDK Runtime Environment (build 11.0.12+7-b1504.28-7817840)
        • All Android licenses accepted.
    
    [✓] Chrome - develop for the web
        • CHROME_EXECUTABLE = C:\Program Files\BraveSoftware\Brave-Browser\Application\brave.exe
    
    [✓] Visual Studio - develop for Windows (Visual Studio Community 2022 17.3.2)
        • Visual Studio at C:\Program Files\Microsoft Visual Studio\2022\Community
        • Visual Studio Community 2022 version 17.3.32819.101
        • Windows 10 SDK version 10.0.19041.0
    
    [✓] Android Studio (version 2021.2)
        • Android Studio at C:\Program Files\Android\Android Studio
        • Flutter plugin can be installed from:
          🔨 https://plugins.jetbrains.com/plugin/9212-flutter
        • Dart plugin can be installed from:
          🔨 https://plugins.jetbrains.com/plugin/6351-dart
        • Java version OpenJDK Runtime Environment (build 11.0.12+7-b1504.28-7817840)
    
    [✓] VS Code (version 1.71.0)
        • VS Code at C:\Users\Nabeel\AppData\Local\Programs\Microsoft VS Code
        • Flutter extension version 3.46.0
    
    [✓] Connected device (3 available)
        • Windows (desktop) • windows • windows-x64    • Microsoft Windows [Version 10.0.22000.918]
        • Chrome (web)      • chrome  • web-javascript • unknown
        • Edge (web)        • edge    • web-javascript • Microsoft Edge 105.0.1343.27
    
    [✓] HTTP Host Availability
        • All required HTTP hosts are available
    
    • No issues found!
    
    flutter doctor -v (Master)
    [✓] Flutter (Channel master, 3.4.0-19.0.pre.192, on Microsoft Windows [Version 10.0.22000.918], locale en-US)
        • Flutter version 3.4.0-19.0.pre.192 on channel master at C:\Users\Nabeel\fvm\versions\master
        • Upstream repository https://github.com/flutter/flutter.git
        • Framework revision 4930444f4a (2 days ago), 2022-09-09 21:58:23 -0400
        • Engine revision f72107f457
        • Dart version 2.19.0 (build 2.19.0-183.0.dev)
        • DevTools version 2.17.0
    
    [✓] Windows Version (Installed version of Windows is version 10 or higher)
    
    [✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
        • Android SDK at C:\android-sdk
        • Platform android-33, build-tools 33.0.0
        • Java binary at: C:\Program Files\Android\Android Studio\jre\bin\java
        • Java version OpenJDK Runtime Environment (build 11.0.12+7-b1504.28-7817840)
        • All Android licenses accepted.
    
    [✓] Chrome - develop for the web
        • CHROME_EXECUTABLE = C:\Program Files\BraveSoftware\Brave-Browser\Application\brave.exe
    
    [✓] Visual Studio - develop for Windows (Visual Studio Community 2022 17.3.2)
        • Visual Studio at C:\Program Files\Microsoft Visual Studio\2022\Community
        • Visual Studio Community 2022 version 17.3.32819.101
        • Windows 10 SDK version 10.0.19041.0
    
    [✓] Android Studio (version 2021.2)
        • Android Studio at C:\Program Files\Android\Android Studio
        • Flutter plugin can be installed from:
          🔨 https://plugins.jetbrains.com/plugin/9212-flutter
        • Dart plugin can be installed from:
          🔨 https://plugins.jetbrains.com/plugin/6351-dart
        • Java version OpenJDK Runtime Environment (build 11.0.12+7-b1504.28-7817840)
    
    [✓] VS Code (version 1.71.0)
        • VS Code at C:\Users\Nabeel\AppData\Local\Programs\Microsoft VS Code
        • Flutter extension version 3.46.0
    
    [✓] Connected device (3 available)
        • Windows (desktop) • windows • windows-x64    • Microsoft Windows [Version 10.0.22000.918]
        • Chrome (web)      • chrome  • web-javascript • unknown
        • Edge (web)        • edge    • web-javascript • Microsoft Edge 105.0.1343.27
    
    [✓] HTTP Host Availability
        • All required HTTP hosts are available
    
    • No issues found!
    
  3. added
    frameworkflutter/packages/flutter repository. See also f: labels.
    a: typographyText rendering, possibly libtxt
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    a: layoutSystemChrome and Framework's Layout Issues
    and removed
    in triagePresently being triaged by the triage team
    on Sep 12, 2022
  4. added
    P2Important issues not at the top of the work list
    on Sep 13, 2022
  5. jason-simmons commented on Sep 23, 2022

    @jason-simmons
    Contributor

    Looked at how this is handled in SkParagraph and found a few issues:

    • OneLineShaper::iterateThroughShapingRegions was failing an assert because it was attempting to shape placeholder regions that mapped to an empty block range.
    • OneLineShaper::iterateThroughShapingRegions was hardcoding the same bidi level for every placeholder. The placeholder's bidi level should match the level of the bidi region that contains the placeholder.
    • The TextLine constructor was reordering the placeholders based on the visual order of the bidi regions. The Flutter framework was painting placeholder widgets in the wrong locations because it assumes that the placeholders remain in the order in which they were added to the input. The getRectsForPlaceholders API has no way to indicate that a placeholder was moved due to bidi reordering.

    Proposed fix: https://skia-review.googlesource.com/c/skia/+/584540

  6. added
    engineflutter/engine related. See also e: labels.
    and removed
    frameworkflutter/packages/flutter repository. See also f: labels.
    on Sep 26, 2022
  7. olof-dev commented on Nov 2, 2022

    @olof-dev
    Contributor

    @jason-simmons thanks for the proposed fix! Do you think the same fix will solve #54400, which is also about incorrectly placed WidgetSpans in RTL?

    Any advice on how long the Skia fix will take to propagate into Flutter? (This issue is unfortunately preventing our app from supporting RTL languages. Will look into forking if it'll be a while before this makes it into Flutter.)

  8. mohanadshaban commented on Aug 14, 2024

    @mohanadshaban

    This issue is still active and not solved ?

  9. 3bua7m3d commented on Aug 15, 2024

    @3bua7m3d

    Why hasn't this issue been resolved yet, despite it being old and important for supporting the Arabic language?

  10. olof-dev commented on Aug 15, 2024

    @olof-dev
    Contributor

    Remember to put a thumbs up on the original issue if you want to highlight it for the Flutter team's attention. I've put the OP's example in a DartPad gist to make it easy to see how things look now:
    https://dartpad.dev/?id=fbf6e013c2dfd0fd33237e53b2d316b9

    It renders differently now to the picture in the original post (at least on web):
    image

    What is the expected result for the OP code? Things that look strange to me, without being a bidi expert:

    1. The "1-" is separated from the "AQWER".
    2. The WidgetSpans and TextSpans look to be in the wrong order.
  11. M97Chahboun commented on Aug 26, 2024

    @M97Chahboun
    Contributor

    any update about this issue ?

  12. iskamal commented on Mar 6, 2025

    @iskamal

    any updates?

  13. raphaelpinel commented on Mar 25, 2025

    @raphaelpinel

    This is an important issue for rtl languages and it would be nice to have it fixed.
    For example, a SizedBox between a text and an icon inside the children of a TextSpan seem to be not visible with rtl languages.
    I wanted to have a text that flows on multiple lines, an icon at the end, and some gap in between.
    Workaround that worked for me was to wrap the icon with a Container with padding. Note that wrapping the TextSpan with a Padding didn't work, as it was putting the text and the icon on 2 different lines.

    RichText(
          text: TextSpan(
                children: [
                  TextSpan(text: label),
                  WidgetSpan(
                    child: Container(
                      padding: EdgeInsetsDirectional.only(start: 8.0),
                      child: Icon(yourIcon),
                    ),
                  ),
                ],
              ),
            )
    
  14. Renzo-Olivares commented on Mar 18, 2026

    @Renzo-Olivares
    Contributor

    Remember to put a thumbs up on the original issue if you want to highlight it for the Flutter team's attention. I've put the OP's example in a DartPad gist to make it easy to see how things look now: dartpad.dev?id=fbf6e013c2dfd0fd33237e53b2d316b9

    It renders differently now to the picture in the original post (at least on web): image

    What is the expected result for the OP code? Things that look strange to me, without being a bidi expert:

    1. The "1-" is separated from the "AQWER".
    2. The WidgetSpans and TextSpans look to be in the wrong order.
    Image

    The above image seems to be the expected behavior on the web given the example below.

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Flutter Demo</title>
      <style>
        /* Mimics the Scaffold and Center widgets */
        body {
          margin: 0;
          height: 100vh;
          display: flex;
          justify-content: center;
          align-items: center;
          background-color: #fafafa;
          font-family: Arial, sans-serif;
        }
    
        /* Mimics the RichText widget with RTL direction and base TextStyle */
        .rich-text {
          direction: rtl; /* Directionality: TextDirection.rtl */
          background-color: rgba(0, 0, 0, 0.5); /* Colors.black.withOpacity(0.5) */
          font-size: 30px; 
          color: #ffffff; /* Added so text is readable against the dark background */
        }
    
        /* Mimics the WidgetSpan + Container combinations */
        .widget-span {
          display: inline-block; /* Allows width/height within a text line */
          /* vertical-align: baseline; (This is CSS default and matches Flutter's default WidgetSpan alignment) */
        }
    
        .red-box {
          background-color: red;
          width: 20px;
          height: 20px;
        }
    
        .green-box {
          background-color: green;
          width: 50px;
          height: 20px;
        }
      </style>
    </head>
    <body>
    
      <!-- 
        The container acts as the RichText.
        The spans with .widget-span act as WidgetSpans.
        The normal spans act as TextSpans.
      -->
      <div class="rich-text"><span class="widget-span red-box"></span><span>1-AQWER</span><span class="widget-span green-box"></span><span>2-BNMVC</span></div>
    
    </body>
    </html>

    Looks like we still need to adjust the widgetspan order.

  15. Renzo-Olivares commented on Mar 18, 2026

    @Renzo-Olivares
    Contributor

    This issue given the comment above regarding the current state of the issue seems like a duplicate of #54400. I'll close this for now, but feel free to re-open if this is not the case.

  16. github-actions commented on Apr 1, 2026

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  17. locked as resolved and limited conversation to collaborators on Apr 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work lista: layoutSystemChrome and Framework's Layout Issuesa: typographyText rendering, possibly libtxtengineflutter/engine related. See also e: labels.found in release: 3.3Found to occur in 3.3found in release: 3.4Found to occur in 3.4has reproducible stepsThe issue has been confirmed reproducible and is ready to work onr: duplicateIssue is closed as a duplicate of an existing issueteam-engineOwned by Engine teamtriaged-engineTriaged by Engine team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions