herald-md
Render Markdown to the terminal with herald's full theming and composability.
When to use |
Installation |
Quick Start |
Elements |
Theming |
Extensions |
Composing |
Examples
herald-md parses Markdown with goldmark (CommonMark + GFM) and renders it to the terminal through herald's typography system - themed headings, styled code blocks, tables, alerts, and more, all controlled by a single Typography instance.
When to use herald-md
glamour is an excellent library for rendering Markdown in the terminal.
herald-md takes a different approach. Paired with herald, it gives you a full typography layer where Markdown is one input format among many. Use it when:
- You want one theme for your entire CLI or TUI - pick a built-in theme (Dracula, Catppuccin, Base16, Charm) or define your own, and both Markdown and programmatic output use it automatically - no separate style configuration needed.
- You need fine-grained customization - functional options and
ColorPalette give you full control over every element.
- You are mixing Markdown with programmatic elements -
Render returns a plain string you can pass directly to herald's Compose alongside other herald calls.
Installation
Requires Go 1.25+.
go get github.com/indaco/herald-md@latest
Quick Start
[!NOTE]
The Go module path is github.com/indaco/herald-md but the package name is heraldmd. Use an import alias: heraldmd "github.com/indaco/herald-md".
package main
import (
"fmt"
"os"
"github.com/indaco/herald"
heraldmd "github.com/indaco/herald-md"
)
func main() {
source, _ := os.ReadFile("doc.md")
ty := herald.New()
fmt.Println(heraldmd.Render(ty, source))
}
Supported elements
| Element |
Markdown syntax |
Herald method |
| Headings H1–H6 |
# H1 … ###### H6 |
H1() – H6() |
| Paragraph |
plain text |
P() |
| Blockquote |
> text |
Blockquote() |
| Fenced code block |
```lang |
CodeBlock(code, lang) |
| Indented code block |
4-space indent |
CodeBlock(code) |
| Horizontal rule |
--- |
HR() |
| Unordered list |
- item |
UL() / NestUL() |
| Ordered list |
1. item |
OL() / NestOL() |
| Bold |
**text** |
Bold() |
| Italic |
*text* |
Italic() |
| Strikethrough |
~~text~~ |
Strikethrough() |
| Inline code |
`code` |
Code() |
| Link |
[label](url) |
Link(label, url) |
| Autolink |
<https://...> |
Link(url) |
| Image |
 |
Link(alt, url) (terminals cannot render images) |
| GFM table |
pipe table syntax |
Table() / TableWithOpts() |
| GitHub alert |
> [!NOTE] etc. |
Alert() / Note() / Tip() etc. |
| Definition list * |
Term + : desc |
DL() |
| Footnote ref * |
[^1] |
FootnoteRef() |
| Footnote section * |
[^1]: text |
FootnoteSection() |
| Inline quotation |
<q>text</q> |
Q() |
| Citation |
<cite>text</cite> |
Cite() |
| Sample output |
<samp>text</samp> |
Samp() |
| Variable |
<var>text</var> |
Var() |
| Keyboard key |
<kbd>text</kbd> |
Kbd() |
| Highlight |
<mark>text</mark> |
Mark() |
| Inserted text |
<ins>text</ins> |
Ins() |
| Deleted text |
<del>text</del> |
Del() |
| Subscript |
<sub>text</sub> |
Sub() |
| Superscript |
<sup>text</sup> |
Sup() |
| Abbreviation |
<abbr>text</abbr> |
Abbr() |
| Underline |
<u>text</u> |
Underline() |
| Small text |
<small>text</small> |
Small() |
Elements marked with * require enabling the corresponding goldmark extension via NewRenderer. All other elements work out of the box with the default GFM configuration.
- Inline HTML tags (
<q>, <cite>, <samp>, <var>, <kbd>, <mark>, <ins>, <del>, <sub>, <sup>, <abbr>, <u>, <small>, <b>, <i>, <s>, <em>, <strong>, <code>) are mapped to the corresponding herald method. Unknown HTML tags pass through as raw text.
- Nested lists are automatically rendered with
NestUL/NestOL when sub-lists are detected, falling back to flat UL/OL for simple lists.
- Column alignment specified in GFM tables (
:-, :-:, -:) is preserved via WithColumnAlign.
Theming
Pass any herald theme to herald.New() and all Markdown output will use it:
ty := herald.New(herald.WithTheme(herald.DraculaTheme()))
fmt.Println(heraldmd.Render(ty, source))
Custom ColorPalette values and individual With* options work the same way - configure the Typography instance once and Render inherits everything.
Custom goldmark extensions
Use NewRenderer to add goldmark extensions beyond the default GFM set:
r := heraldmd.NewRenderer(
goldmark.WithExtensions(extension.Footnote),
)
fmt.Println(r.Render(ty, source))
The package-level Render function uses a default renderer with GFM enabled.
Composing with herald
Because Render returns a string, it composes directly with other herald output via ty.Compose:
ty := herald.New()
page := ty.Compose(
ty.H1("My App"),
heraldmd.Render(ty, readmeBytes), // readmeBytes loaded via os.ReadFile(...)
ty.HR(),
ty.KVGroup([][2]string{
{"Version", "1.0.0"},
{"License", "MIT"},
}),
)
fmt.Println(page)
Examples
Runnable examples are in the examples/ directory:
Core (0xx)
| Example |
Description |
Run |
| 000_render-file |
Render a Markdown file with the default theme; accepts any .md as argument |
go run ./examples/000_render-file/ |
Extensions (1xx)
Examples in this range are separate Go modules with their own go.mod to keep extra dependencies out of herald-md's core. Run them with cd into the example directory first.
| Example |
Description |
Run |
| 100_definition-list |
Custom goldmark extension: definition lists rendered as herald DL |
cd examples/100_definition-list && go run . |
License
This project is licensed under the MIT License - see the LICENSE file for details.