Themes & Styles
GptMarkdown v1.2.1 has three customization layers. They never overlap — each serves a distinct purpose.
Style object
Appearance: colours, sizes, padding, fonts
GptMarkdownStyleSheet
Builder
Structure: replace the widget entirely
codeBuilder, blockQuoteBuilder, …
Theme data
Defaults for the whole app or a subtree
GptMarkdownThemeData
The rule: style object for looks, builder for structure. A builder loses every future improvement to that component; a style object keeps it.
Layer 1 — GptMarkdownStyleSheet
Pass a GptMarkdownStyleSheet to a single widget. Every field is optional; anything unset keeps the package default — adding a style sheet never changes how existing content looks.
1// Per-widget: only this GptMarkdown is affected.
2GptMarkdown(
3 text,
4 styleSheet: const GptMarkdownStyleSheet(
5 blockQuote: BlockQuoteStyle(barWidth: 4, barColor: Colors.indigo),
6 codeBlock: CodeBlockStyle(
7 borderRadius: Radius.circular(12),
8 showCopyButton: true,
9 ),
10 latex: LatexStyle(scrollBlockHorizontally: true),
11 ),
12)All 12 style fields show reference
| Field | Type | Controls |
|---|---|---|
| blockQuote | BlockQuoteStyle? | Bar width/colour/radius, background, padding, margin, text style |
| heading | HeadingStyle? | Text style overlay, padding, showDivider, divider colour/thickness/padding |
| link | LinkStyle? | Colour, hover colour, decoration, decorationThickness, fontWeight |
| inlineCode | InlineCodeStyle? | Font, fontSizeFactor, colour, background, border, radius, padding, boxHeightStyle |
| list | ListStyle? | Bullet size/colour/shape, marker text style, indent, gapAfterMarker |
| checkbox | CheckboxStyle? | Size, checked/unchecked/check colour, borderRadius, gapAfterBox, interactive |
| codeBlock | CodeBlockStyle? | Background, border, radius, padding, font, showLanguageLabel, copy button, labels |
| table | TableStyle? | Border colour/width/radius, cellPadding, header background/text style, row stripe |
| image | ImageStyle? | Border radius, padding, fit, maxWidth, maxHeight |
| hr | HrStyle? | Thickness, colour, padding |
| sourceTag | SourceTagStyle? | Background, text style, size, shape, padding (the [1] citation chip) |
| latex | LatexStyle? | Text style, padding, background, border radius, scrollBlockHorizontally |
Layer 2 — App-wide via GptMarkdownThemeData
Register GptMarkdownThemeData as a ThemeData extension. The brightness parameter is required so default colours are derived correctly. Light and dark themes each need their own instance.
1// App-wide: register GptMarkdownThemeData as a ThemeData extension.
2// Light and dark each need their own — the extension lives on ThemeData.
3MaterialApp(
4 theme: ThemeData.light().copyWith(
5 extensions: [
6 GptMarkdownThemeData(
7 brightness: Brightness.light,
8 styleSheet: const GptMarkdownStyleSheet(
9 link: LinkStyle(decoration: TextDecoration.none),
10 table: TableStyle(cellPadding: EdgeInsets.all(10)),
11 ),
12 // Legacy heading fields — still work; a styleSheet.heading wins field-by-field.
13 h1: const TextStyle(fontSize: 28, fontWeight: FontWeight.w800),
14 linkColor: Colors.indigo,
15 autoAddDividerLineAfterH1: true,
16 ),
17 ],
18 ),
19 darkTheme: ThemeData.dark().copyWith(
20 extensions: [
21 GptMarkdownThemeData(
22 brightness: Brightness.dark,
23 linkColor: Colors.lightBlueAccent,
24 ),
25 ],
26 ),
27 home: const MyApp(),
28)Layer 3 — Scoped via GptMarkdownTheme
GptMarkdownTheme is an InheritedWidget that overrides the ThemeData extension for its subtree. Use it when one screen needs different styling without changing the global theme.
1// Scoped: wrap specific widgets with GptMarkdownTheme.
2// Takes priority over the ThemeData extension.
3GptMarkdownTheme(
4 gptThemeData: GptMarkdownThemeData(
5 brightness: Brightness.light,
6 h1: const TextStyle(fontSize: 28, fontWeight: FontWeight.w900),
7 linkColor: Colors.deepPurple,
8 hrLineColor: Colors.grey.shade300,
9 hrLineThickness: 1.5,
10 hrLinePadding: const EdgeInsets.symmetric(vertical: 8),
11 ),
12 child: GptMarkdown(content),
13)Merge & precedence
The merge happens per field, not per object. A widget-level value wins over the theme value for the same field, and any field left unset falls back to the package default.
1// Precedence — per field, not per object:
2// widget styleSheet → theme styleSheet → package default
3//
4// With both set, the blockquote gets barWidth: 4 from the widget
5// AND barColor from the theme. Overriding one value never discards the rest.
6
7MaterialApp(
8 theme: ThemeData(
9 extensions: [
10 GptMarkdownThemeData(
11 brightness: Brightness.light,
12 styleSheet: const GptMarkdownStyleSheet(
13 blockQuote: BlockQuoteStyle(barColor: Colors.indigo),
14 ),
15 ),
16 ],
17 ),
18 home: GptMarkdown(
19 text,
20 styleSheet: const GptMarkdownStyleSheet(
21 blockQuote: BlockQuoteStyle(barWidth: 4), // barColor still comes from theme
22 ),
23 ),
24)Legacy GptMarkdownThemeData fields
These fields from v1.1.x are still fully supported. A styleSheet.heading or styleSheet.link value wins over them field-by-field where both are set.
Legacy field reference show reference
| Field | Type | Notes |
|---|---|---|
| brightness | Brightness | Required. Drives default colour derivation. |
| h1 – h6 | TextStyle? | Per-level heading text style. HeadingStyle.textStyle is merged over these. |
| highlightColor | Color? | Legacy inline-code chip fill. Equivalent to inlineCode: InlineCodeStyle(backgroundColor: …). |
| linkColor | Color? | Default link colour. Superseded by styleSheet.link.color. |
| linkHoverColor | Color? | Link hover colour (web). Superseded by styleSheet.link.hoverColor. |
| hrLineColor | Color? | Horizontal rule colour. Superseded by styleSheet.hr.color. |
| hrLineThickness | double? | Rule stroke width. Superseded by styleSheet.hr.thickness. |
| hrLinePadding | EdgeInsets? | Padding around rules. Superseded by styleSheet.hr.padding. |
| autoAddDividerLineAfterH1 | bool? | Insert a divider after h1. Superseded by HeadingStyle.showDivider. |
| inlineCode | InlineCodeStyle? | App-wide inline code style (v1.2.0). Partial — unset fields derive from ColorScheme. |
| styleSheet | GptMarkdownStyleSheet? | App-wide per-component styles (v1.2.0). |
Dark mode needs its own extension
GptMarkdownThemeData lives on ThemeData, so theme: and darkTheme: each need one — with brightness: set to match, or the derived defaults will be wrong.
