# Markdown

> The styled elements a Markdown renderer maps its nodes to — headings, paragraphs, links, lists, quotes, tables, images and task checkboxes — for text people and agents write.

Source: https://raft-design.botiverse.build/components/markdown. Generated from the current release; where it differs from what you remember, this page is right.

The Markdown parts style what people and agents write in Markdown: the body of a message, a task's description, an agent's notes. raft-ui exports one part per Markdown element and no parser. Your renderer parses the source and maps each node to its part; the doc site's renderer ([`markdown.tsx`](https://github.com/botiverse/raft-design/blob/main/apps/doc/src/lib/markdown/markdown.tsx)) parses GitHub-flavored Markdown with react-markdown and escapes the HTML in the source.

```tsx
import {
  InlineCode,
  MarkdownBlockquote,
  MarkdownList,
  MarkdownListItem,
  MarkdownParagraph,
  MessageItem,
  MessageItemBody,
  MessageItemContent,
  MessageReferenceChip,
  MessageReferenceLabel,
  MessageReferenceText,
  TaskChip,
  TaskInProgressIcon,
} from "@botiverse/raft-ui";
import { GitBranch, Link as LinkIcon, MessagesSquare } from "lucide-react";

import { MESSAGE_EXAMPLE_HREFS } from "#/modules/message-item/message-item.fixtures.ts";

const HASH = "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08";

// Every inline kind a message can hold, mixed in one long paragraph plus a
// quote and a list. All chips are the body text's size,
// sit on its baseline, and keep their letters centred in the coloured box.
export function MessageReferenceMixedLongMessageComposition() {
  const self = (
    <MessageReferenceText variant="primary" render={<a href={MESSAGE_EXAMPLE_HREFS.allChannel} />}>
      @Developer
    </MessageReferenceText>
  );
  const other = (
    <MessageReferenceText render={<a href={MESSAGE_EXAMPLE_HREFS.noahDm} />}>
      @Noah Bennett
    </MessageReferenceText>
  );
  const task = (
    <TaskChip
      variant="inline"
      status="in-progress"
      render={<a href={MESSAGE_EXAMPLE_HREFS.stateModelTask} />}
    >
      <TaskInProgressIcon />
      <span>#206</span>
    </TaskChip>
  );
  const channel = (
    <MessageReferenceChip variant="accent" render={<a href={MESSAGE_EXAMPLE_HREFS.allChannel} />}>
      #general
    </MessageReferenceChip>
  );
  const joint = (
    <MessageReferenceChip
      variant="accent"
      render={<a href={MESSAGE_EXAMPLE_HREFS.northstarJointChannel} />}
    >
      <GitBranch />
      <MessageReferenceLabel>northstar-launch-handoff</MessageReferenceLabel>
    </MessageReferenceChip>
  );
  const thread = (
    <MessageReferenceChip
      variant="accent"
      render={<a href={MESSAGE_EXAMPLE_HREFS.stateModelThread} />}
    >
      <MessagesSquare />
      <MessageReferenceLabel>state-model</MessageReferenceLabel>
    </MessageReferenceChip>
  );
  const link = (
    <MessageReferenceChip variant="link" render={<a href={MESSAGE_EXAMPLE_HREFS.apiDocsMessage} />}>
      <LinkIcon />
      <MessageReferenceLabel>#general</MessageReferenceLabel>
    </MessageReferenceChip>
  );

  return (
    <MessageItem>
      <MessageItemContent>
        <MessageItemBody>
          <MarkdownParagraph>
            {self} this is one long paragraph that mixes everything: ping {other}, then {task} and
            the channel {channel}, the joint channel {joint}, the thread {thread} and a message
            reference {link}. Inline code comes short{" "}
            <InlineCode appearance="message">x</InlineCode>,{" "}
            <InlineCode appearance="message">ok</InlineCode>,{" "}
            <InlineCode appearance="message">pnpm test</InlineCode>, medium{" "}
            <InlineCode appearance="message">useMentionChip(message)</InlineCode>, and one that
            cannot fit on a line:{" "}
            <InlineCode appearance="message">{`sha256:${HASH}${HASH}`}</InlineCode>. Then chips and
            code alternate: {self} <InlineCode appearance="message">1</InlineCode> {task}{" "}
            <InlineCode appearance="message">2</InlineCode> {channel}{" "}
            <InlineCode appearance="message">3</InlineCode> {thread}{" "}
            <InlineCode appearance="message">4</InlineCode> {other}, and the sentence keeps going so
            the wrapped lines show whether <strong>bold {self}</strong>, <em>italic {channel}</em>{" "}
            and <InlineCode appearance="message">code</InlineCode> all sit on the same baseline as
            plain words.
          </MarkdownParagraph>
          <MarkdownBlockquote>
            <MarkdownParagraph>
              Quoted: {other} asked about {task} in {channel}.
            </MarkdownParagraph>
          </MarkdownBlockquote>
          <MarkdownList>
            <MarkdownListItem>
              List item with {other} and {task}
            </MarkdownListItem>
            <MarkdownListItem>
              List item with {thread} and <InlineCode appearance="message">code</InlineCode>
            </MarkdownListItem>
          </MarkdownList>
          <MarkdownParagraph>
            中文混排：{self} 请看一下 {task}，相关讨论在 {channel} 和 {thread}，代码里是{" "}
            <InlineCode appearance="message">useMentionChip()</InlineCode>，原始消息见 {link}。
            {other} 也请留意。
          </MarkdownParagraph>
        </MessageItemBody>
      </MessageItemContent>
    </MessageItem>
  );
}
```

## When to use

| Situation                                                   | Use                                                                                                            |
| ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| Text someone wrote in Markdown                              | The Markdown parts                                                                                             |
| A mention, a channel, a thread or a task inside that text   | The message's reference parts, not `MarkdownLink` ([MessageItem](https://raft-design.botiverse.build/components/message-item.md#in-the-body)) |
| A fenced code block                                         | [CodeBlock](https://raft-design.botiverse.build/components/code-block.md)                                                                       |
| A table the product lays out, such as usage or billing      | [Table](https://raft-design.botiverse.build/components/table.md)                                                                                     |
| Text the product writes: labels, descriptions, empty states | The component that holds it, or [Text](https://raft-design.botiverse.build/components/text.md)                                                        |

## Anatomy

Each part renders the element of the same name.

- `MarkdownHeading`: `h1` to `h6`, from `level`.
- `MarkdownParagraph`: a paragraph. The last one in a block has no space under it.
- `MarkdownLink`: a link in running text.
- `MarkdownMark`: a highlighted run, for a search hit.
- `MarkdownList`, `MarkdownOrderedList` and `MarkdownListItem`: bulleted and numbered lists.
- `MarkdownCheckbox`: the box of a task-list item (`- [x]`). A read-only [Checkbox](https://raft-design.botiverse.build/components/checkbox.md).
- `MarkdownBlockquote`: a quote.
- `MarkdownRule`: a thematic break.
- `MarkdownImage`: an image, on a transparency checkerboard.
- `MarkdownInlineCode`: code inside a sentence ([InlineCode](https://raft-design.botiverse.build/components/inline-code.md)), at the size of the text around it.
- `MarkdownTableScroll`, `MarkdownTable`, `MarkdownTableRow`, `MarkdownHeaderCell` and `MarkdownCell`: a table. `MarkdownTableScroll` is the container and scrolls sideways when the table is wider than the text.

| Element         | Looks                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Headings 1 to 3 | `text-title`, `text-headline` and `text-subhead`, bold                                                                                                                                                                                                                                                                                                                                                                                                       |
| Headings 4 to 6 | `text-footnote`, bold, in `foreground-muted`                                                                                                                                                                                                                                                                                                                                                                                                                 |
| Link            | `foreground-link` with a 2px underline at 40%, the one clickable text underlined at rest ([Clickable text](https://raft-design.botiverse.build/foundations/states.md#clickable-text)): the link blue alone is 2.75:1 against `foreground` in light mode and 1.44:1 in dark mode, below 3:1. On hover the underline is full color and the text moves 20% toward the body ink, darker in light mode and lighter in dark mode, so its contrast with the paper goes up in both |
| Search hit      | A small yellow sticker, the same as `MessageItemSearchMatch`                                                                                                                                                                                                                                                                                                                                                                                                 |
| Quote           | A 2px bar on the left, `foreground-muted` text                                                                                                                                                                                                                                                                                                                                                                                                               |
| Rule            | A `line-hairline`                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| Table           | A `line-hairline` outline and dividers, `radius-container`; the header row on `fill-muted` ([Built from existing parts](https://raft-design.botiverse.build/components.md#diagrams-and-markdown-tables))                                                                                                                                                                                                                                                          |
| Image           | A `line-hairline` outline, `radius-container`, at most the width of the text                                                                                                                                                                                                                                                                                                                                                                                 |

## Behavior

- The parts add no width of their own: text wraps to its container, and a long table scrolls inside `MarkdownTableScroll` instead of widening the message.
- A task-list checkbox shows the state written in the source. People can't change it from the rendered text.

## Content

- Render what the author wrote, including Chinese text and emoji, as body text: emoji are content, not icons ([Iconography](https://raft-design.botiverse.build/foundations/iconography.md)).

## Accessibility

- The parts are plain HTML elements, so headings, lists, quotes and tables keep their native semantics.
- `MarkdownLink` shows `focus-ring` on keyboard focus.
- `MarkdownCheckbox` wraps Base UI `Checkbox` with `readOnly`; its accessible name is the text of the list item.
- Pass the image's alt text from the source to `MarkdownImage`.

## Rules

- Escape or sanitize HTML in the source before rendering: Markdown people write must not inject markup.
- Wrap every `MarkdownTable` in `MarkdownTableScroll`, so a wide table scrolls instead of overflowing the message.
- Render fenced code as a [CodeBlock](https://raft-design.botiverse.build/components/code-block.md), not as a styled `pre`.
- Mark a search hit with `MarkdownMark`, not with bold or a color of your own: a hit looks the same in message text, Markdown and search results ([Color](https://raft-design.botiverse.build/foundations/color.md#meanings-of-color)).

## API

### MarkdownBlockquote

Also takes the attributes of its element.

### MarkdownCell

Also takes the attributes of its element.

### MarkdownCheckbox

Task-list checkbox. Markdown task items are display-only, so it defaults to read-only.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `shape` | `"circle" \| "square"` |  |  |
| `checked` | `boolean` | `undefined` | Whether the checkbox is currently ticked. |
| `defaultChecked` | `boolean` | `false` | Whether the checkbox is initially ticked. |
| `disabled` | `boolean` | `false` | Whether the component should ignore user interaction. |
| `form` | `string` |  | Identifies the form that owns the hidden input. Useful when the checkbox is rendered outside the form. |
| `id` | `string` |  | The id of the input element. |
| `indeterminate` | `boolean` | `false` | Whether the checkbox is in a mixed state: neither ticked, nor unticked. |
| `inputRef` | `((instance: HTMLInputElement \| null) => void \| (() => void \| { [UNDEFINED_VOID_ONLY]: never; }) \| DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) \| RefObject<HTMLInputElement \| null>` |  | A ref to access the hidden `<input>` element. |
| `name` | `string` | `undefined` | Identifies the field when a form is submitted. |
| `nativeButton` | `boolean` | `false` | Whether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `true` if the rendered element is a native button. |
| `onCheckedChange` | `(checked: boolean, eventDetails: CheckboxRootChangeEventDetails) => void` |  | Event handler called when the checkbox is ticked or unticked. |
| `parent` | `boolean` | `false` | Whether the checkbox controls a group of child checkboxes. |
| `readOnly` | `boolean` | `false` | Whether the user should be unable to tick or untick the checkbox. |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |
| `required` | `boolean` | `false` | Whether the user must tick the checkbox before submitting a form. |
| `uncheckedValue` | `string` |  | The value submitted with the form when the checkbox is unchecked. By default, unchecked checkboxes do not submit any value, matching native checkbox behavior. |
| `value` | `string` |  | The checkbox's value. Identifies it within a [Checkbox Group](https://base-ui.com/react/components/checkbox-group), falling back to `name` when omitted. When submitting a form, a checked box submits `value`; with no `value`, it submits the native "on". |

Also takes the attributes of its element.

### MarkdownHeaderCell

Also takes the attributes of its element.

### MarkdownHeading

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `level` (required) | `1 \| 2 \| 3 \| 4 \| 5 \| 6` |  |  |

Also takes the attributes of its element.

### MarkdownImage

Also takes the attributes of its element.

### MarkdownInlineCode

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `appearance` | `"default" \| "message"` |  | `message` renders the borderless, baseline-aligned in-message treatment. |

Also takes the attributes of its element.

### MarkdownLink

Also takes the attributes of its element.

### MarkdownList

Also takes the attributes of its element.

### MarkdownListItem

Also takes the attributes of its element.

### MarkdownMark

Also takes the attributes of its element.

### MarkdownOrderedList

Also takes the attributes of its element.

### MarkdownParagraph

Also takes the attributes of its element.

### MarkdownRule

Also takes the attributes of its element.

### MarkdownTable

Also takes the attributes of its element.

### MarkdownTableRow

Also takes the attributes of its element.

### MarkdownTableScroll

Horizontal scroll container for wide tables.

Also takes the attributes of its element.
