DEV Community

Cover image for Mastering💪🏻 RichText in Flutter: Style Like a Pro😎!
Hitesh Meghwal
Hitesh Meghwal

Posted on

Mastering💪🏻 RichText in Flutter: Style Like a Pro😎!

Flutter's RichText widget is a powerful tool that allows developers to create sophisticated text layouts with multiple styles, colors, and interactive elements within a single text block. Whether you're building a social media app with hashtags and mentions, a reading app with styled content, or simply want to add visual flair to your text, mastering RichText is essential for creating polished Flutter applications.

What is RichText?

The RichText widget displays text that uses multiple different styles. Unlike the basic Text widget which applies a single style to the entire string, RichText allows you to style individual portions of text differently using TextSpan objects.

Basic RichText Structure

Every RichText widget requires a TextSpan as its text property. Here's the basic structure:

RichText(
  text: TextSpan(
    children: [
      TextSpan(text: "Hello "),
      TextSpan(
        text: "World",
        style: TextStyle(fontWeight: FontWeight.bold),
      ),
    ],
  ),
)
Enter fullscreen mode Exit fullscreen mode

Essential TextSpan Properties

Text Styling

  • text: The actual text content
  • style: TextStyle object for formatting
  • children: List of nested TextSpan objects
  • recognizer: Gesture recognizer for tap interactions

Common TextStyle Properties

  • color: Text color
  • fontSize: Size of the text
  • fontWeight: Bold, normal, etc.
  • fontStyle: Italic, normal
  • decoration: Underline, strikethrough, etc.
  • backgroundColor: Highlight color behind text

Real-World Examples

1. Social Media Post with Hashtags and Mentions

socialMedia

RichText(
  text: TextSpan(
    style: TextStyle(color: Colors.black, fontSize: 16),
    children: [
      TextSpan(text: "Just finished an amazing "),
      TextSpan(
        text: "#Flutter",
        style: TextStyle(
          color: Colors.blue,
          fontWeight: FontWeight.w500,
        ),
        recognizer: TapGestureRecognizer()
          ..onTap = () => print("Hashtag tapped"),
      ),
      TextSpan(text: " project! Thanks to "),
      TextSpan(
        text: "@FlutterDev",
        style: TextStyle(
          color: Colors.blue,
          fontWeight: FontWeight.w500,
        ),
        recognizer: TapGestureRecognizer()
          ..onTap = () => print("Mention tapped"),
      ),
      TextSpan(text: " for the inspiration! 🚀"),
    ],
  ),
)
Enter fullscreen mode Exit fullscreen mode

2. Pricing Display with Strikethrough

pricinDisplay

RichText(
  text: TextSpan(
    style: TextStyle(fontSize: 18),
    children: [
      TextSpan(text: "Price: "),
      TextSpan(
        text: "\$99.99",
        style: TextStyle(
          color: Colors.grey,
          decoration: TextDecoration.lineThrough,
        ),
      ),
      TextSpan(text: " "),
      TextSpan(
        text: "\$49.99",
        style: TextStyle(
          color: Colors.green,
          fontWeight: FontWeight.bold,
          fontSize: 20,
        ),
      ),
    ],
  ),
)
Enter fullscreen mode Exit fullscreen mode

3. Terms and Conditions Link

termsNCondition

RichText(
  text: TextSpan(
    style: TextStyle(color: Colors.black),
    children: [
      TextSpan(text: "By signing up, you agree to our "),
      TextSpan(
        text: "Terms and Conditions",
        style: TextStyle(
          color: Colors.blue,
          decoration: TextDecoration.underline,
        ),
        recognizer: TapGestureRecognizer()
          ..onTap = () => _openTermsAndConditions(),
      ),
      TextSpan(text: " and "),
      TextSpan(
        text: "Privacy Policy",
        style: TextStyle(
          color: Colors.blue,
          decoration: TextDecoration.underline,
        ),
        recognizer: TapGestureRecognizer()
          ..onTap = () => _openPrivacyPolicy(),
      ),
    ],
  ),
)
Enter fullscreen mode Exit fullscreen mode

4. Code Snippet Display

codeSnippet

RichText(
  text: TextSpan(
    style: TextStyle(
      fontFamily: 'Courier',
      backgroundColor: Colors.grey[100],
    ),
    children: [
      TextSpan(
        text: "void ",
        style: TextStyle(color: Colors.blue),
      ),
      TextSpan(
        text: "main",
        style: TextStyle(color: Colors.purple),
      ),
      TextSpan(
        text: "() {\n  ",
        style: TextStyle(color: Colors.black),
      ),
      TextSpan(
        text: "print",
        style: TextStyle(color: Colors.blue),
      ),
      TextSpan(
        text: "('Hello, Flutter!');\n}",
        style: TextStyle(color: Colors.black),
      ),
    ],
  ),
)
Enter fullscreen mode Exit fullscreen mode

Advanced Techniques

1. Nested TextSpans

You can nest TextSpan objects to create complex hierarchies:

nestedTextspans

RichText(
  text: TextSpan(
    text: "Welcome to ",
    style: TextStyle(color: Colors.black),
    children: [
      TextSpan(
        text: "Flutter",
        style: TextStyle(
          color: Colors.blue,
          fontWeight: FontWeight.bold,
        ),
        children: [
          TextSpan(
            text: " Development",
            style: TextStyle(
              fontStyle: FontStyle.italic,
              color: Colors.green,
            ),
          ),
        ],
      ),
    ],
  ),
)
Enter fullscreen mode Exit fullscreen mode

2. Custom Gesture Recognizers

class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  TapGestureRecognizer? _tapRecognizer;

  @override
  void initState() {
    super.initState();
    _tapRecognizer = TapGestureRecognizer()
      ..onTap = _handleTap;
  }

  @override
  void dispose() {
    _tapRecognizer?.dispose();
    super.dispose();
  }

  void _handleTap() {
    // Handle tap
  }

  @override
  Widget build(BuildContext context) {
    return RichText(
      text: TextSpan(
        text: "Click ",
        children: [
          TextSpan(
            text: "here",
            style: TextStyle(color: Colors.blue),
            recognizer: _tapRecognizer,
          ),
        ],
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

3. Dynamic Text Building

dynamicText

Widget buildDynamicRichText(List<String> words) {
  return RichText(
    text: TextSpan(
      children: words.map((word) {
        if (word.startsWith('#')) {
          return TextSpan(
            text: word + ' ',
            style: TextStyle(color: Colors.blue),
            recognizer: TapGestureRecognizer()
              ..onTap = () => _handleHashtag(word),
          );
        } else if (word.startsWith('@')) {
          return TextSpan(
            text: word + ' ',
            style: TextStyle(color: Colors.orange),
            recognizer: TapGestureRecognizer()
              ..onTap = () => _handleMention(word),
          );
        } else {
          return TextSpan(
            text: word + ' ',
            style: TextStyle(color: Colors.black),
          );
        }
      }).toList(),
    ),
  );
}
Enter fullscreen mode Exit fullscreen mode

RichText vs Text.rich

Flutter also provides Text.rich() constructor which is essentially a wrapper around RichText with additional features from the Text widget:

// Using Text.rich
Text.rich(
  TextSpan(
    children: [
      TextSpan(text: "Hello "),
      TextSpan(
        text: "World",
        style: TextStyle(fontWeight: FontWeight.bold),
      ),
    ],
  ),
  textAlign: TextAlign.center, // Additional Text widget properties
)

// Equivalent RichText
RichText(
  textAlign: TextAlign.center,
  text: TextSpan(
    children: [
      TextSpan(text: "Hello "),
      TextSpan(
        text: "World",
        style: TextStyle(fontWeight: FontWeight.bold),
      ),
    ],
  ),
)
Enter fullscreen mode Exit fullscreen mode

Performance Tips

  1. Dispose Gesture Recognizers: Always dispose of TapGestureRecognizer objects to prevent memory leaks.

  2. Reuse TextStyle Objects: Create TextStyle objects as constants when possible to reduce memory allocation.

  3. Minimize Rebuilds: Use const constructors where possible and avoid creating new TextSpan objects in build methods.

// Good: Reusable styles
static const TextStyle _linkStyle = TextStyle(
  color: Colors.blue,
  decoration: TextDecoration.underline,
);

static const TextStyle _boldStyle = TextStyle(
  fontWeight: FontWeight.bold,
);
Enter fullscreen mode Exit fullscreen mode

Common Use Cases

1. Multi-language Support

RichText(
  textDirection: TextDirection.rtl, // For RTL languages
  text: TextSpan(
    children: [
      TextSpan(text: "مرحبا "),
      TextSpan(
        text: "بالعالم",
        style: TextStyle(fontWeight: FontWeight.bold),
      ),
    ],
  ),
)
Enter fullscreen mode Exit fullscreen mode

2. Mathematical Expressions

RichText(
  text: TextSpan(
    children: [
      TextSpan(text: "E = mc"),
      TextSpan(
        text: "2",
        style: TextStyle(
          fontSize: 12,
          fontFeatures: [FontFeature.superscripts()],
        ),
      ),
    ],
  ),
)
Enter fullscreen mode Exit fullscreen mode
  • FontFeature.superscripts() tells Flutter to render that character as a superscript (if supported by the font).

  • Make sure the font you're using supports superscripts. Most default fonts do, but custom fonts may not.

  • fontSize is reduced a bit on the superscript for visual consistency.

3. Highlight Search Results

heighlightSearch

Widget highlightSearchResults(String text, String query) {
  if (query.isEmpty) {
    return Text(text);
  }

  List<TextSpan> spans = [];
  text.splitMapJoin(
    RegExp(query, caseSensitive: false),
    onMatch: (m) {
      spans.add(TextSpan(
        text: m[0],
        style: TextStyle(backgroundColor: Colors.yellow),
      ));
      return '';
    },
    onNonMatch: (n) {
      spans.add(TextSpan(text: n));
      return '';
    },
  );

  return RichText(text: TextSpan(children: spans));
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

Flutter's RichText widget is a powerful tool for creating styled, interactive text content. Key takeaways:

  • Always dispose of gesture recognizers to prevent memory leaks
  • Use consistent styling and reusable TextStyle objects
  • Consider performance with large text content
  • Perfect for social media apps, e-commerce, and content-rich applications

Master RichText to create professional, engaging user experiences in your Flutter apps📱!
✨ If you found this blog helpful and want to explore more Flutter projects, feel free to check out my GitHub repositories at Github — and don’t forget to follow for more updates!

Happy Coding!!💓

Top comments (0)