Search packages, repositories and app categories

Package detailsv0.1.0

span_builder

Facilitates creation of spans from plain text and provides automated disposal of GestureRecognizers

30-day downloads
11
Likes
18
Pub points
40

Install package

flutter pub add span_builder

Package Overview

Package selection guidance compiled from public package information, community data, and project usage.

SpanBuilder is a Flutter/Dart package designed to simplify the creation of rich text spans from plain text, enabling easy integration of styled text, links, and interactive elements. It automatically manages the disposal of GestureRecognizers, preventing memory leaks and improving performance. Ideal for dynamic text rendering with embedded interactions, such as clickable hashtags or mentions. The package supports clean, declarative syntax for building complex text layouts without manual lifecycle management.

Use cases

  • Building interactive rich text with clickable elements
  • Rendering formatted text with mixed styles
  • Creating mention or hashtag parsers
  • Automating gesture recognizer cleanup
  • Displaying dynamic content with embedded actions

Key features

  • Automatic GestureRecognizer disposal
  • Simple span creation from plain text
  • Supports rich text styling
  • Reduces boilerplate code
  • Prevents memory leaks

Suitable for

  • Developers building chat interfaces
  • Apps with dynamic text content
  • Projects requiring interactive text elements
  • Teams prioritizing clean code and maintenance

Considerations

  • Limited to text-based UI components
  • No built-in support for complex layouts
  • Requires understanding of TextSpan structure
  • Not suitable for non-text rendering needs
  • Depends on Flutter's Text widget ecosystem

Original README

Original README snapshot from the linked source repository. Visit the repository for the latest content.

span_builder

Facilitates creation of spans from plain text and provides an automated disposal of GestureRecognizers.

Description

Given some plain text, e.g.: "The quick brown fox" allows you to apply multiple spans at multiple positions. Positions can be specified by a matching word (whereText), e.g. "brown" and/or range from=10, to=15. Spans are subclasses of InlineSpan. If the span you are trying to apply is TextSpan you don't need to pass whereText as it will be inferred from text within the provided span.

Once you are done using SpanBuilder, use build() to return calculated list of spans. Spans can't overlap.

Usage:
final spans = SpanBuilder("The quick brown fox")
  .apply(TextSpan(text: "brown", style: TextStyle(fontWeight: FontWeight.bold)))
  .apply(TextSpan(text: "🦊"), whereText: "fox")
  .build()

From there you can use these spans in your RichText, e.g.:

RichText(
  text: TextSpan(children: spans)
)

If you plan to make your text "tappable" read on.

Handling GestrueRecognizer (text taps)

If you try passing GestrueRecognizer as a field in TextSpan it will get stripped away - HERE IS WHY.

TL;DR: We don't want to leak GestureRecognizer but TextSpan has no idea about the lifecycle of Widget so you need a stateful widget to keep a reference to the recognizer untill you're done with it. Sounds like a mess, right?

The workaround is to provide a builder for the recognizer like this:

apply(TextSpan(text: "jumps"),
  recognizerBuilder: () => TapGestureRecognizer()..onTap = () {
    // your code here
  })

Then you can use this SpanBuilder together with SpanBuilderWidget which will manage creating and disposing of TapGestrueRecognizer at the right time:

SpanBuilderWidget(
  text: SpanBuilder("fox jumps")
    ..apply(TextSpan(text: "jumps"),
      recognizerBuilder: () => TapGestureRecognizer()..onTap = () {
        // your code here
      })
)

If you care only about onTap interaction you can use this API shortcut:

apply(TextSpan(text: "jumps"),
  onTap: () {
    // your code here
  }
)
Testing:

There are little resources on how to test RichText in general. For this reason there is helper testing library span_builder_test that can help you verify state of your spans in your UI tests.

void main() {
  testWidgets('MyApp test', (WidgetTester tester) async {
    await tester.pumpWidget(MyApp());

    final spanFinder = find.byKey(span_key);

    expect(spanFinder, findsOneWidget);
    final allSpans = tester.findSpans(spanFinder).length;
    expect(allSpans, 8);

    final foxSpans = tester.findSpans(spanFinder, predicate: (span) {
      return span is TextSpan && span.text == "🦊"; 
    });
    expect(foxSpans.length, 1);
  });
}

span_builder_test

WidgetTest helpers and extensions for testing span_builder

Getting Started

This is a companion library to the span_builder library intended to help you write test wherever that library is used.

Usage
Related Content

Categories

Source repository

Projects using this package

No data available yet.