hashtagable_v3

pub package pub points License: MIT

Widgets, functions, and controllers to implement hashtag, mention, and cashtag decorated text in Flutter.

Detects words starting with # (hashtags), @ (mentions), $ (cashtags/crypto/stocks), or any custom prefixes of your choice like Twitter / X, Bluesky, Instagram, and Reddit.

Demo


What's New in v3.1.0 ๐Ÿš€

  • HashTagTextEditingController: A lightweight TextEditingController that brings instant tag decoration and typing callbacks to standard Flutter TextField, TextFormField, and CupertinoTextField without widget wrappers!
  • Cashtag Support ($): Tag financial tickers and cryptocurrencies (e.g. $BTC, $TSLA, $ETH) using decorateCashtag: true.
  • Custom Prefixes: Highlight any custom symbols using customPrefixes: ['#', '@', '$', '!'].
  • Modern Flutter & TextScaler: Full support for Flutter 3.22+, TextScaler, and WidgetStateProperty.
  • Extraction Utilities: hasMentions(), hasCashtags(), extractMentions(), and extractCashtags().

Installation

Add hashtagable_v3 to your pubspec.yaml:

dependencies:
  hashtagable_v3: ^3.1.0

Usage

Use HashTagTextEditingController directly in any standard TextField or TextFormField:

final controller = HashTagTextEditingController(
  text: "Hello #flutter and @openneom with \$BTC!",
  decoratedStyle: const TextStyle(
    color: Colors.blue,
    fontWeight: FontWeight.bold,
  ),
  basicStyle: const TextStyle(
    color: Colors.black,
  ),
  decorateAtSign: true,
  decorateCashtag: true,
  onTagChanged: (tag) {
    print("Currently typing tag: $tag");
  },
  onTagFinished: () {
    print("Tag completed");
  },
);

@override
Widget build(BuildContext context) {
  return TextFormField(
    controller: controller,
    decoration: const InputDecoration(
      hintText: "What's happening? Use #tags, @mentions, or \$cashtags",
    ),
  );
}

2. ReadOnly Display Text

If you want to display decorated text with clickable tags, use HashTagText:

HashTagText(
  text: "#Welcome to #hashtagable with @openneom and \$BTC!",
  decoratedStyle: const TextStyle(fontSize: 18, color: Colors.blue),
  basicStyle: const TextStyle(fontSize: 18, color: Colors.black),
  decorateAtSign: true,
  decorateCashtag: true,
  onTap: (tag) {
    print("User tapped tag: $tag");
  },
)

3. As HashTagTextField (Legacy Component)

You can also continue using the standalone HashTagTextField:

HashTagTextField(
  decoratedStyle: const TextStyle(fontSize: 14, color: Colors.blue),
  basicStyle: const TextStyle(fontSize: 14, color: Colors.black),
  decorateAtSign: true,
  decorateCashtag: true,
  onDetectionTyped: (tag) {
    print("Typing: $tag");
  },
)

Custom Symbols & Prefixes

To decorate arbitrary symbols (for instance #, @, $, !, or ยง), pass customPrefixes:

HashTagText(
  text: "Highlight !important notice and ?query along with #topic",
  customPrefixes: const ['!', '?', '#'],
  decoratedStyle: const TextStyle(color: Colors.deepOrange),
  basicStyle: const TextStyle(color: Colors.black),
  onTap: (symbolTag) => print(symbolTag),
)

Useful Functions

Detection & Extraction

// Hashtags (#)
hasHashTags("Hello #World"); // true
extractHashTags("#Hello #Flutter Dart #ThankYou"); // ["#Hello", "#Flutter", "#ThankYou"]

// Mentions (@)
hasMentions("Ping @emmanuel and @openneom"); // true
extractMentions("Ping @emmanuel and @openneom"); // ["@emmanuel", "@openneom"]

// Cashtags ($)
hasCashtags(r"Buy $BTC and $ETH"); // true
extractCashtags(r"Buy $BTC and $ETH"); // ["$BTC", "$ETH"]

Rich Text Span Generation

Generate custom TextSpan trees anywhere in your UI:

final TextSpan span = getHashTagTextSpan(
  decoratedStyle: const TextStyle(color: Colors.blue),
  basicStyle: const TextStyle(color: Colors.black),
  source: "Check out #hashtagable by @openneom!",
  decorateAtSign: true,
  onTap: (tag) => print(tag),
);

Supported Languages & Rules

  • Supports English, Japanese, Korean, Spanish, Arabic, Thai, Norwegian, German, and more.
  • Respects punctuation and emojis: stops decoration when hitting emojis or special punctuation.
  • Requires whitespace (or start-of-line) before tag prefixes to avoid false positives in email addresses or URLs.

Contributors & Attribution

Issues & feature requests welcome at github.com/emmanuel-montoya/hashtagable_v3.