Custom Components

Register your own Flutter widgets as Markdown elements. Block components replace whole lines; inline components can appear inside a sentence alongside text. Both use regular expressions to match custom syntax in the Markdown string.

components

Block-level

Match multi-line patterns, replace with any widget

inlineComponents

Inline

Match within a line, rendered alongside text

sourceTagBuilder

Citations

Render AI citation/source references

Block component

A block component that turns <callout type="warning">...</callout> into a styled callout box — useful when your AI model is prompted to output structured annotations.

callout_component.dart
1import 'package:flutter/material.dart'; 2import 'package:gpt_markdown/gpt_markdown.dart'; 3 4// A custom block component that renders a styled callout box. 5// Triggered when the AI outputs: <callout type="warning">text</callout> 6 7final calloutComponent = MarkdownComponent( 8 exp: RegExp(r'<callout type="(\w+)">(.*?)</callout>', dotAll: true), 9 builder: (context, match, style) { 10 final type = match.group(1) ?? 'info'; 11 final text = match.group(2) ?? ''; 12 final colors = { 13 'warning': (Colors.orange.shade50, Colors.orange.shade400), 14 'error': (Colors.red.shade50, Colors.red.shade400), 15 'info': (Colors.blue.shade50, Colors.blue.shade400), 16 }; 17 final (bg, border) = colors[type] ?? colors['info']!; 18 return Container( 19 margin: const EdgeInsets.symmetric(vertical: 8), 20 padding: const EdgeInsets.all(12), 21 decoration: BoxDecoration( 22 color: bg, 23 border: Border(left: BorderSide(color: border, width: 4)), 24 borderRadius: BorderRadius.circular(4), 25 ), 26 child: Text(text, style: style), 27 ); 28 }, 29); 30 31// Register it: 32GptMarkdown( 33 content, 34 components: [calloutComponent], 35)

Inline component

An inline component that renders <badge color="green">NEW</badge> as a colored pill badge, rendered within a sentence.

badge_component.dart
1import 'package:flutter/material.dart'; 2import 'package:gpt_markdown/gpt_markdown.dart'; 3 4// A custom inline component that renders colored badges. 5// Triggered by: <badge color="green">NEW</badge> 6 7final badgeComponent = InlineMarkdownComponent( 8 exp: RegExp(r'<badge color="(\w+)">(.*?)</badge>'), 9 builder: (context, match, style) { 10 final color = match.group(1) ?? 'blue'; 11 final label = match.group(2) ?? ''; 12 final colorMap = { 13 'green': Colors.green, 14 'blue': Colors.blue, 15 'red': Colors.red, 16 'orange': Colors.orange, 17 }; 18 final c = colorMap[color] ?? Colors.blue; 19 return Container( 20 padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), 21 decoration: BoxDecoration( 22 color: c.withOpacity(0.15), 23 borderRadius: BorderRadius.circular(4), 24 border: Border.all(color: c.withOpacity(0.4)), 25 ), 26 child: Text( 27 label, 28 style: style?.copyWith( 29 color: c.shade700, 30 fontSize: 11, 31 fontWeight: FontWeight.w600, 32 letterSpacing: 0.3, 33 ), 34 ), 35 ); 36 }, 37); 38 39// Register it: 40GptMarkdown( 41 content, 42 inlineComponents: [badgeComponent], 43)

Registering multiple

Pass any number of components in the list — they are tested in order.

registration.dart
1GptMarkdown( 2 content, 3 components: [ 4 calloutComponent, 5 sectionDividerComponent, 6 codePlaygroundComponent, 7 ], 8 inlineComponents: [ 9 badgeComponent, 10 tooltipComponent, 11 ], 12)

Citation / source tags

The package has first-class support for AI citation tags via sourceTagBuilder.

source_tags.dart
1// The package has built-in support for AI citation tags like: 2// <source>1</source> or [1] style references. 3// Use sourceTagBuilder to render them your way: 4 5GptMarkdown( 6 content, 7 sourceTagBuilder: (context, sources) { 8 return Row( 9 mainAxisSize: MainAxisSize.min, 10 children: sources.map((src) => GestureDetector( 11 onTap: () => openSource(src), 12 child: Container( 13 margin: const EdgeInsets.only(left: 2), 14 padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 1), 15 decoration: BoxDecoration( 16 color: Colors.blue.shade50, 17 borderRadius: BorderRadius.circular(4), 18 ), 19 child: Text( 20 src, 21 style: const TextStyle(fontSize: 10, color: Colors.blue), 22 ), 23 ), 24 )).toList(), 25 ); 26 }, 27)

Tip — prompt your AI to use custom tags

Custom components work best when you include tag instructions in your system prompt. For example: "When highlighting a warning, wrap it in <callout type="warning">...</callout>."