Overview
The MarkdownRenderable component renders Markdown content with full support for tables, code blocks, inline formatting, and more. It uses the marked parser internally and provides syntax highlighting for code blocks via Tree-sitter.
Basic Usage
import { MarkdownRenderable, SyntaxStyle } from "@opentui/core"
const syntaxStyle = SyntaxStyle.fromStyles({
"markup.heading": { fg: parseColor("#58A6FF"), bold: true },
"markup.link": { fg: parseColor("#58A6FF"), underline: true },
default: { fg: parseColor("#E6EDF3") },
})
const markdown = new MarkdownRenderable(renderer, {
content: "# Hello World\n\nThis is **bold** text.",
syntaxStyle,
conceal: true,
})
Props
Markdown content to render.
Syntax styling configuration for markdown elements and code blocks.
Hide formatting markers (e.g., **, *, “, []()).When true: **bold** → boldWhen false: **bold** → **bold**
Tree-sitter client for syntax highlighting code blocks. Uses default client if not provided.
Enable streaming mode for incremental content updates. Keeps trailing tokens unstable to handle incomplete content.
Configuration for rendered markdown tables.
renderNode
(token: Token, context: RenderNodeContext) => Renderable | undefined
Custom node renderer. Return a Renderable to override default rendering, or undefined to use default.
Table Options
tableOptions.widthMode
'content' | 'full'
default:"'full'"
Column sizing strategy:
'content': Columns fit to intrinsic content width
'full': Columns expand to fill available width
tableOptions.columnFitter
'uniform' | 'proportional'
default:"'proportional'"
Column fitting method when shrinking constrained tables.
tableOptions.wrapMode
'none' | 'char' | 'word'
default:"'word'"
Text wrapping strategy for table cell content.
Padding applied on all sides of each table cell.
Enable/disable table border rendering.
tableOptions.borderStyle
BorderStyle
default:"'single'"
Border style for markdown tables ('single', 'double', etc.).
Border color. Defaults to conceal style color.
Enable selection support on markdown tables.
Supported Markdown Features
Headings
# Heading 1
## Heading 2
### Heading 3
Text Formatting
**bold text**
*italic text*
~~strikethrough~~
`inline code`
Links
[Link text](https://example.com)

Lists
- Unordered item 1
- Unordered item 2
1. Ordered item 1
2. Ordered item 2
Blockquotes
> This is a blockquote
> with multiple lines
Code Blocks
```typescript
const message = "Hello World"
console.log(message)
```
Tables
| Feature | Status | Priority |
|---|---|---|
| Table alignment | Done | High |
| Conceal mode | Working | Medium |
Horizontal Rules
Methods
clearCache()
Force re-render by clearing the parse cache.
refreshStyles()
Re-render blocks with updated styles without rebuilding parse state.
markdown.syntaxStyle = newSyntaxStyle
markdown.refreshStyles()
Examples
GitHub Dark Theme
const syntaxStyle = SyntaxStyle.fromStyles({
"markup.heading": { fg: parseColor("#58A6FF"), bold: true },
"markup.heading.1": { fg: parseColor("#00FF88"), bold: true, underline: true },
"markup.heading.2": { fg: parseColor("#00D7FF"), bold: true },
"markup.bold": { fg: parseColor("#F0F6FC"), bold: true },
"markup.strong": { fg: parseColor("#F0F6FC"), bold: true },
"markup.italic": { fg: parseColor("#F0F6FC"), italic: true },
"markup.raw": { fg: parseColor("#A5D6FF"), bg: parseColor("#161B22") },
"markup.link": { fg: parseColor("#58A6FF"), underline: true },
"markup.link.url": { fg: parseColor("#58A6FF"), underline: true },
"punctuation.special": { fg: parseColor("#8B949E") },
default: { fg: parseColor("#E6EDF3") },
})
const markdown = new MarkdownRenderable(renderer, {
content: markdownContent,
syntaxStyle,
conceal: true,
})
Markdown with Tables
const content = `
# Project Status
| Feature | Status | Priority |
|---|---|---|
| Table alignment | **Done** | High |
| Conceal mode | *Working* | Medium |
| Theme switching | **Done** | Low |
`
const markdown = new MarkdownRenderable(renderer, {
content,
syntaxStyle,
tableOptions: {
widthMode: "full",
cellPadding: 1,
borders: true,
borderStyle: "single",
},
})
Streaming Mode
const markdown = new MarkdownRenderable(renderer, {
content: "",
syntaxStyle,
streaming: true, // Enable incremental updates
})
// Simulate streaming content
let position = 0
const fullContent = "# Streaming\n\nThis content arrives gradually..."
const interval = setInterval(() => {
const chunk = fullContent.slice(0, position + 10)
markdown.content = chunk
position += 10
if (position >= fullContent.length) {
markdown.streaming = false // Finalize
clearInterval(interval)
}
}, 100)
Custom Table Styling
const markdown = new MarkdownRenderable(renderer, {
content: markdownWithTables,
syntaxStyle,
tableOptions: {
widthMode: "content",
wrapMode: "word",
cellPadding: 2,
borders: true,
borderStyle: "double",
borderColor: "#4ECDC4",
selectable: true,
},
})
Conceal Toggle
const markdown = new MarkdownRenderable(renderer, {
content: "**bold** and *italic* text",
syntaxStyle,
conceal: true,
})
// Toggle conceal on keypress
renderer.keyInput.on("keypress", (key) => {
if (key.name === "c") {
markdown.conceal = !markdown.conceal
}
})
Custom Node Renderer
const markdown = new MarkdownRenderable(renderer, {
content: markdownContent,
syntaxStyle,
renderNode: (token, context) => {
// Custom rendering for specific token types
if (token.type === "heading" && token.depth === 1) {
// Return custom renderable for h1 elements
return new CustomHeaderRenderable(renderer, {
text: token.text,
})
}
// Return undefined to use default rendering
return undefined
},
})
Syntax Style Groups
Markdown uses the following syntax style groups:
markup.heading, markup.heading.1 through markup.heading.6
markup.bold, markup.strong
markup.italic
markup.list
markup.quote
markup.raw, markup.raw.block, markup.raw.inline
markup.link, markup.link.label, markup.link.url
punctuation.special
conceal (for concealed formatting markers)
default
Properties
content
Get or set the markdown content.
markdown.content = "# New Content"
const current = markdown.content
syntaxStyle
Get or set the syntax style.
markdown.syntaxStyle = newSyntaxStyle
conceal
Get or set conceal mode.
markdown.conceal = false // Show formatting markers
streaming
Get or set streaming mode.
markdown.streaming = true
tableOptions
Get or set table rendering options.
markdown.tableOptions = {
widthMode: "content",
cellPadding: 2,
}
- Uses AST-based parsing with
marked for accurate Markdown parsing
- Implements caching for repeated content to avoid redundant parsing
- Smart width calculation accounting for concealed characters
- Incremental rendering in streaming mode
- Efficient table rendering with change detection
- Text - Plain text display
- Code - Syntax-highlighted code blocks
- TextTable - Table component (used internally)