---
title: Markdown
url: "https://native-sdk.dev/docs/components/markdown"
docs_index: /llms.txt
lastUpdated: 2026-10-16
---

> For an index of all documentation, see [/llms.txt](/llms.txt).

Use `markdown` to render a string as selectable native content. It supports a GFM subset, including pipe tables and a limited set of HTML elements. `source` is required, accepts one model binding, and the element takes no children.

Pass loaded images through `images` and handle links through `on-link`. Bare URLs are linked automatically. `on-details` and model-owned `details-expanded` flags control disclosure blocks; `issue-link-base` turns references such as `#123` into links. Fenced blocks use the [code](/docs/components/code) component.

## Markup

```html
<markdown source="{release_notes}" images="{markdown_images}" on-link="open_link" issue-link-base="https://github.com/vercel-labs/native/issues/"></markdown>
```

## Programmatic construction (Zig)

The builder is the `canvas.markdown` module, parameterized over the app's Msg type; `on_link` pairs with `Ui.linkMsg(.tag)`.

```zig
const Md = native_sdk.canvas.markdown.Markdown(Msg);

Md.view(ui, model.release_notes, .{
    .images = model.markdown_images,
    .on_link = Ui.linkMsg(.open_link),
    .issue_link_base = "https://github.com/vercel-labs/native/issues/",
})
```

Image discovery writes canonical, entity-decoded URLs into caller-owned bounded storage. Consume each `value()` while that storage is alive, copy accepted sources into the model, and use the same bytes for both `fx.loadImage` and the eventual `ResolvedImage.source` mapping:

```zig
var source_storage: [canvas.markdown.max_markdown_images]canvas.markdown.CollectedImageSource = undefined;
const sources = canvas.markdown.collectImageSources(model.release_notes, &source_storage);
for (sources) |*collected| {
    const source = collected.value();
    // Validate the scheme, copy source into the model, then issue fx.loadImage.
}
```

## HTML subset

README- and comment-style HTML is lowered onto native presentation rather than passed to a browser:

- Text: `<b>`, `<strong>`, `<i>`, `<em>`, `<var>`, `<s>`, `<strike>`, `<del>`, `<u>`, `<ins>`, `<code>`, `<kbd>`, `<samp>`, `<tt>`, `<mark>`, `<small>`, `<sub>`, and `<sup>`.
- Content: `<a href>`, `<img src alt width height>`, `<br>`, `<wbr>`, `<q>`, HTML comments, core named entities, and numeric entities. A leading image in a paragraph, heading, list item, blockquote, or pipe-table cell becomes a native image when `images` contains a successful `canvas.markdown.ResolvedImage` mapping for its source; unresolved and mid-paragraph images fall back to alt text. The view never fetches remote media — discover bounded sources with `canvas.markdown.collectImageSources`, read each caller-owned `CollectedImageSource` through `value()`, load it through `fx.loadImage`, retain successful ids and dimensions in the model, and pass mappings with that canonical source back on the next rebuild.
- Blocks and wrappers: `<h1>` through `<h6>`, `<p>`, `<blockquote>`, `<pre>`, `<hr>`, list items, and the common `<div align="center">` README pattern. Harmless list, table, and container wrappers are accepted as readable native content; use Markdown pipe tables for full native table layout. `<details>` and `<summary>` retain their controlled expansion behavior.

This is a sanitized native subset, not a DOM. CSS, scripts, forms, embeds, event attributes, and arbitrary HTML do not execute; unsupported or malformed tags remain literal text. Only `href`, image `src`/`alt`/dimensions, and block `align` affect presentation.

## Attributes

| Attribute          | Description                                                                                                                                                                                                                                                           |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `source`           | markdown: one \{binding} producing the markdown text (a \[]const u8 field or fn; arena fns work). Required.                                                                                                                                                           |
| `images`           | markdown: one \{binding} producing \[]const canvas.markdown.ResolvedImage (arena fns work). Each mapping pairs a leading image source with an image id already loaded and registered through fx.loadImage plus its decoded dimensions; views never perform image I/O. |
| `on-link`          | markdown: bare Msg tag dispatched on link press; its payload is the URL (\[]const u8 variant).                                                                                                                                                                        |
| `on-details`       | markdown: bare Msg tag dispatched on a \<details> summary press; its payload is the block index (usize variant).                                                                                                                                                      |
| `details-expanded` | markdown: \{binding} naming a \[]const bool iterable of expanded flags, in details-block document order.                                                                                                                                                              |
| `issue-link-base`  | markdown: literal URL prefix or one \{binding}; '#123' refs become links to base ++ number (ghissue:// or https\://github.com/owner/repo/issues/).                                                                                                                    |

---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/agents.md](/agents.md)