Skip to content

MarkdownViewer

Added in version 0.11.0

A Widget to display Markdown content with an optional Table of Contents.

  • Focusable
  • Container

Note

This Widget adds browser-like functionality on top of the Markdown widget.

Example

The following example displays Markdown from a string and a Table of Contents.

MarkdownExampleApp ▼ Ⅰ Markdown Viewer ├── Ⅱ FeaturesMarkdown Viewer ├── Ⅱ Tables ├── Ⅱ Code BlocksThis is an example of Textual's MarkdownViewer widget. └── Ⅱ Litany Against Fear Features Markdown syntax and extensions are supported. • Typography emphasisstronginline code etc. • Headers • Lists (bullet and ordered) • Syntax highlighted code blocks • Tables! Tables Tables are displayed in a DataTable widget. ────────────────────────────────────────────────────────────── NameTypeDefaultDescription ────────────────────────────────────────────────────────────── show_headerboolTrueShow the table header ────────────────────────────────────────────────────────────── fixed_rowsint0Number of fixed rows▃▃ ────────────────────────────────────────────────────────────── fixed_columnsint0Number of fixed columns ────────────────────────────────────────────────────────────── zebra_stripesboolFalseDisplay alternating colors on rows ────────────────────────────────────────────────────────────── header_heightint1Height of header row ────────────────────────────────────────────────────────────── show_cursorboolTrueShow a cell cursor ────────────────────────────────────────────────────────────── Code Blocks

from textual.app import App, ComposeResult
from textual.widgets import MarkdownViewer

EXAMPLE_MARKDOWN = """\
# Markdown Viewer

This is an example of Textual's `MarkdownViewer` widget.


## Features

Markdown syntax and extensions are supported.

- Typography *emphasis*, **strong**, `inline code` etc.
- Headers
- Lists (bullet and ordered)
- Syntax highlighted code blocks
- Tables!

## Tables

Tables are displayed in a DataTable widget.

| Name            | Type   | Default | Description                        |
| --------------- | ------ | ------- | ---------------------------------- |
| `show_header`   | `bool` | `True`  | Show the table header              |
| `fixed_rows`    | `int`  | `0`     | Number of fixed rows               |
| `fixed_columns` | `int`  | `0`     | Number of fixed columns            |
| `zebra_stripes` | `bool` | `False` | Display alternating colors on rows |
| `header_height` | `int`  | `1`     | Height of header row               |
| `show_cursor`   | `bool` | `True`  | Show a cell cursor                 |


## Code Blocks

Code blocks are syntax highlighted.

```python
class ListViewExample(App):
    def compose(self) -> ComposeResult:
        yield ListView(
            ListItem(Label("One")),
            ListItem(Label("Two")),
            ListItem(Label("Three")),
        )
        yield Footer()
```

## Litany Against Fear

I must not fear.
Fear is the mind-killer.
Fear is the little-death that brings total obliteration.
I will face my fear.
I will permit it to pass over me and through me.
And when it has gone past, I will turn the inner eye to see its path.
Where the fear has gone there will be nothing. Only I will remain.
"""


class MarkdownExampleApp(App):
    def compose(self) -> ComposeResult:
        markdown_viewer = MarkdownViewer(EXAMPLE_MARKDOWN, show_table_of_contents=True)
        markdown_viewer.code_indent_guides = False
        yield markdown_viewer


if __name__ == "__main__":
    app = MarkdownExampleApp()
    app.run()

Reactive Attributes

Name Type Default Description
show_table_of_contents bool True Whether a Table of Contents should be displayed with the Markdown.

Messages

This widget posts no messages.

Bindings

This widget has no bindings.

Component Classes

This widget has no component classes.

See Also


Bases: VerticalScroll

A Markdown viewer widget.

Parameters:

Name Type Description Default
markdown str | None

String containing Markdown, or None to leave blank.

None
show_table_of_contents bool

Show a table of contents in a sidebar.

True
name str | None

The name of the widget.

None
id str | None

The ID of the widget in the DOM.

None
classes str | None

The CSS classes of the widget.

None
parser_factory Callable[[], MarkdownIt] | None

A factory function to return a configured MarkdownIt instance. If None, a "gfm-like" parser is used.

None
open_links bool

Open links automatically. If you set this to False, you can handle the LinkClicked events.

True

document property

document: Markdown

The Markdown document widget.

show_table_of_contents class-attribute instance-attribute

show_table_of_contents = show_table_of_contents

Show the table of contents?

table_of_contents property

table_of_contents: MarkdownTableOfContents

The table of contents widget.

NavigatorUpdated

Bases: Message

Navigator has been changed (clicked link etc).

back async

back()

Go back one level in the history.

forward async

forward()

Go forward one level in the history.

go async

go(location)

Navigate to a new document path.

textual.widgets.markdown

TableOfContentsType module-attribute

TableOfContentsType: TypeAlias = (
    "list[tuple[int, str, str | None]]"
)

Information about the table of contents of a markdown document.

The triples encode the level, the label, and the optional block id of each heading.

Markdown

Markdown(
    markdown=None,
    *,
    name=None,
    id=None,
    classes=None,
    parser_factory=None,
    open_links=True
)

Bases: Widget

Parameters:

Name Type Description Default
markdown str | None

String containing Markdown or None to leave blank for now.

None
name str | None

The name of the widget.

None
id str | None

The ID of the widget in the DOM.

None
classes str | None

The CSS classes of the widget.

None
parser_factory Callable[[], MarkdownIt] | None

A factory function to return a configured MarkdownIt instance. If None, a "gfm-like" parser is used.

None
open_links bool

Open links automatically. If you set this to False, you can handle the LinkClicked events.

True

BLOCKS class-attribute instance-attribute

BLOCKS: dict[str, type[MarkdownBlock]] = {
    "h1": MarkdownH1,
    "h2": MarkdownH2,
    "h3": MarkdownH3,
    "h4": MarkdownH4,
    "h5": MarkdownH5,
    "h6": MarkdownH6,
    "hr": MarkdownHorizontalRule,
    "paragraph_open": MarkdownParagraph,
    "blockquote_open": MarkdownBlockQuote,
    "bullet_list_open": MarkdownBulletList,
    "ordered_list_open": MarkdownOrderedList,
    "list_item_ordered_open": MarkdownOrderedListItem,
    "list_item_unordered_open": MarkdownUnorderedListItem,
    "table_open": MarkdownTable,
    "tbody_open": MarkdownTBody,
    "thead_open": MarkdownTHead,
    "tr_open": MarkdownTR,
    "th_open": MarkdownTH,
    "td_open": MarkdownTD,
    "fence": MarkdownFence,
    "code_block": MarkdownFence,
}

Mapping of block names on to a widget class.

BULLETS class-attribute instance-attribute

BULLETS = ['• ', '▪ ', '‣ ', '⭑ ', '◦ ']

Unicode bullets used for unordered lists.

source property

source: str

The markdown source.

table_of_contents property

table_of_contents: TableOfContentsType

The document's table of contents.

LinkClicked

LinkClicked(markdown, href)

Bases: Message

A link in the document was clicked.

control property
control: Markdown

The Markdown widget containing the link clicked.

This is an alias for LinkClicked.markdown and is used by the on decorator.

href instance-attribute
href: str = unquote(href)

The link that was selected.

markdown instance-attribute
markdown: Markdown = markdown

The Markdown widget containing the link clicked.

TableOfContentsSelected

TableOfContentsSelected(markdown, block_id)

Bases: Message

An item in the TOC was selected.

block_id instance-attribute
block_id: str = block_id

ID of the block that was selected.

control property
control: Markdown

The Markdown widget where the selected item is.

This is an alias for TableOfContentsSelected.markdown and is used by the on decorator.

markdown instance-attribute
markdown: Markdown = markdown

The Markdown widget where the selected item is.

TableOfContentsUpdated

TableOfContentsUpdated(markdown, table_of_contents)

Bases: Message

The table of contents was updated.

control property
control: Markdown

The Markdown widget associated with the table of contents.

This is an alias for TableOfContentsUpdated.markdown and is used by the on decorator.

markdown instance-attribute
markdown: Markdown = markdown

The Markdown widget associated with the table of contents.

table_of_contents instance-attribute
table_of_contents: TableOfContentsType = table_of_contents

Table of contents.

append

append(markdown)

Append to markdown.

Parameters:

Name Type Description Default
markdown str

A fragment of markdown to be appended.

required

Returns:

Type Description
AwaitComplete

An optionally awaitable object. Await this to ensure that the markdown has been append by the next line.

get_block_class

get_block_class(block_name)

Get the block widget class.

Parameters:

Name Type Description Default
block_name str

Name of the block.

required

Returns:

Type Description
type[MarkdownBlock]

A MarkdownBlock class

get_stream classmethod

get_stream(markdown)

Get a MarkdownStream instance to stream Markdown in the background.

If you append to the Markdown document many times a second, it is possible the widget won't be able to update as fast as you write (occurs around 20 appends per second). It will still work, but the user will have to wait for the UI to catch up after the document has be retrieved.

Using a MarkdownStream will combine several updates in to one as necessary to keep up with the incoming data.

example:

# self.get_chunk is a hypothetical method that retrieves a
# markdown fragment from the network
@work
async def stream_markdown(self) -> None:
    markdown_widget = self.query_one(Markdown)
    container = self.query_one(VerticalScroll)
    container.anchor()

    stream = Markdown.get_stream(markdown_widget)
    try:
        while (chunk:= await self.get_chunk()) is not None:
            await stream.write(chunk)
    finally:
        await stream.stop()

Parameters:

Name Type Description Default
markdown Markdown

A Markdown widget instance.

required

Returns:

Type Description
MarkdownStream

The Markdown stream object.

goto_anchor

goto_anchor(anchor)

Try and find the given anchor in the current document.

Parameters:

Name Type Description Default
anchor str

The anchor to try and find.

required
Note

The anchor is found by looking at all of the headings in the document and finding the first one whose slug matches the anchor.

Note that the slugging method used is similar to that found on GitHub.

Returns:

Type Description
bool

True when the anchor was found in the current document, False otherwise.

load async

load(path)

Load a new Markdown document.

Parameters:

Name Type Description Default
path Path

Path to the document.

required

Raises:

Type Description
OSError

If there was some form of error loading the document.

Note

The exceptions that can be raised by this method are all of those that can be raised by calling Path.read_text.

sanitize_location staticmethod

sanitize_location(location)

Given a location, break out the path and any anchor.

Parameters:

Name Type Description Default
location str

The location to sanitize.

required

Returns:

Type Description
Path

A tuple of the path to the location cleaned of any anchor, plus

str

the anchor (or an empty string if none was found).

unhandled_token

unhandled_token(token)

Process an unhandled token.

Parameters:

Name Type Description Default
token Token

The MarkdownIt token to handle.

required

Returns:

Type Description
MarkdownBlock | None

Either a widget to be added to the output, or None.

update

update(markdown)

Update the document with new Markdown.

Parameters:

Name Type Description Default
markdown str

A string containing Markdown.

required

Returns:

Type Description
AwaitComplete

An optionally awaitable object. Await this to ensure that all children have been mounted.

MarkdownBlock

MarkdownBlock(
    markdown, token, source_range=None, *args, **kwargs
)

Bases: Static

The base class for a Markdown Element.

COMPONENT_CLASSES class-attribute instance-attribute

COMPONENT_CLASSES = {'em', 'strong', 's', 'code_inline'}

These component classes target standard inline markdown styles. Changing these will potentially break the standard markdown formatting.

Class Description
code_inline Target text that is styled as inline code.
em Target text that is emphasized inline.
s Target text that is styled inline with strikethrough.
strong Target text that is styled inline with strong.

source property

source: str | None

The source of this block if known, otherwise None.

action_link(href)

Called on link click.

build_from_token

build_from_token(token)

Build inline block content from its source token.

Parameters:

Name Type Description Default
token Token

The token from which this block is built.

required

MarkdownFence

MarkdownFence(markdown, token, code)

Bases: MarkdownBlock

A fence Markdown block.

MarkdownStream

MarkdownStream(markdown_widget)

An object to manage streaming markdown.

This will accumulate markdown fragments if they can't be rendered fast enough.

This object is typically created by the Markdown.get_stream method.

start

start()

Start the updater running in the background.

No need to call this, if the object was created by Markdown.get_stream.

stop async

stop()

Stop the stream and await its finish.

write async

write(markdown_fragment)

Append or enqueue a markdown fragment.

Parameters:

Name Type Description Default
markdown_fragment str

A string to append at the end of the document.

required

MarkdownTableOfContents

MarkdownTableOfContents(
    markdown,
    name=None,
    id=None,
    classes=None,
    disabled=False,
)

Bases: Widget

Displays a table of contents for a markdown document.

Parameters:

Name Type Description Default
markdown Markdown

The Markdown document associated with this table of contents.

required
name str | None

The name of the widget.

None
id str | None

The ID of the widget in the DOM.

None
classes str | None

The CSS classes for the widget.

None
disabled bool

Whether the widget is disabled or not.

False

markdown instance-attribute

markdown: Markdown = markdown

The Markdown document associated with this table of contents.

table_of_contents class-attribute instance-attribute

table_of_contents = reactive[Optional[TableOfContentsType]](
    None, init=False
)

Underlying data to populate the table of contents widget.

rebuild_table_of_contents

rebuild_table_of_contents(table_of_contents)

Rebuilds the tree representation of the table of contents data.

Parameters:

Name Type Description Default
table_of_contents TableOfContentsType

Table of contents.

required

watch_table_of_contents

watch_table_of_contents(table_of_contents)

Triggered when the table of contents changes.