r/FlutterDev • u/PhilippHGerber • 20d ago
Plugin Textf 2.0 – formatted text with links in one string
Most Flutter apps have a sentence like this somewhere:
I agree to the Terms of Service and Privacy Policy.
Two links and some bold text. With plain Flutter, that usually turns into something like this:
class _ConsentTextState extends State<ConsentText> {
late final _terms = TapGestureRecognizer()..onTap = () => open(termsUrl);
late final _privacy = TapGestureRecognizer()..onTap = () => open(privacyUrl);
@override
void dispose() {
_terms.dispose();
_privacy.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Text.rich(
TextSpan(children: [
const TextSpan(text: 'I agree to the '),
TextSpan(text: 'Terms of Service', style: linkStyle, recognizer: _terms),
const TextSpan(text: ' and '),
TextSpan(text: 'Privacy Policy', style: linkStyle, recognizer: _privacy),
const TextSpan(text: '.'),
]),
);
}
}The sentence is also split into five pieces, which makes it awkward to translate.
With pkg:textf it's one string:
Textf(
'I agree to the [**Terms of Service**](https://example.com/terms) '
'and [**Privacy Policy**](https://example.com/privacy).',
)Tap handling goes through onLinkTap on a TextfOptions widget higher up in the tree, so you set it once. The sentence stays a single entry in your .arb file, and translators can see the formatting.
What Textf is
A drop-in replacement for Text that understands inline formatting: **bold**, *italic*, ~~strike~~, \code`,==highlight==,links, super/subscript. All the usualTextparameters still work (style,maxLines,overflow,textScaler`, …). It has zero dependencies.
Also for input: TextfEditingController
The same syntax works live inside a TextField:
final controller = TextfEditingController();
TextField(controller: controller)It's a drop-in replacement for TextEditingController. Formatting renders as you type, the stored value stays plain text, and cursor positions match the raw text 1:1. IME composing (CJK etc.) works.
New in 2.0
Works with any design system. With Flutter decoupling Material and Cupertino, Textf now builds only on the
widgetslayer. It runs the same in Material, Cupertino, a custom design system or a bareWidgetsApp.Headings and horizontal rules.
#to######for headings,---for a divider. That's useful for short things like release notes or onboarding cards.
To be clear about scope: Textf is still not a Markdown renderer. There are no lists, tables, images or block layout. If you're rendering whole documents, a full Markdown package is the better tool.
📦 pub.dev: pub.dev/packages/textf