---
title: Markdown
description: AST builder functions and utilities for programmatic message formatting.
type: reference
---

The SDK uses [mdast](https://github.com/syntax-tree/mdast) (Markdown AST) as the canonical format for message formatting. Each adapter converts the AST to the platform's native format.

```typescript
import {
  root, paragraph, text, strong, emphasis, strikethrough,
  inlineCode, codeBlock, link, blockquote,
  parseMarkdown, stringifyMarkdown, toPlainText, walkAst,
  tableToAscii, tableElementToAscii,
} from "chat";
```

## Node builders

### root

Root node — the required top-level wrapper for an AST.

```typescript
root([
  paragraph([text("Hello, world!")]),
])
```

<TypeTable
  type={{
    children: {
      description: 'Top-level content nodes (paragraphs, code blocks, blockquotes, lists).',
      type: 'Content[]',
    },
  }}
/>

### paragraph

A paragraph block.

```typescript
paragraph([text("Hello "), strong([text("world")])])
```

### text

Plain text node.

```typescript
text("Hello, world!")
```

### strong

**Bold** text.

```typescript
strong([text("important")])
```

### emphasis

_Italic_ text.

```typescript
emphasis([text("emphasized")])
```

### strikethrough

~~Strikethrough~~ text.

```typescript
strikethrough([text("removed")])
```

### inlineCode

`Inline code` span.

```typescript
inlineCode("const x = 1")
```

### codeBlock

Fenced code block with optional language.

```typescript
codeBlock("const x = 1;", "typescript")
```

<TypeTable
  type={{
    value: {
      description: 'Code content.',
      type: 'string',
    },
    lang: {
      description: 'Language identifier for syntax highlighting.',
      type: 'string | undefined',
    },
  }}
/>

### link

Hyperlink.

```typescript
link("https://example.com", [text("click here")])
link("https://example.com", [text("click here")], "tooltip title")
```

<TypeTable
  type={{
    url: {
      description: 'Link URL.',
      type: 'string',
    },
    children: {
      description: 'Link text content.',
      type: 'Content[]',
    },
    title: {
      description: 'Optional tooltip text.',
      type: 'string | undefined',
    },
  }}
/>

### blockquote

Block quotation.

```typescript
blockquote([paragraph([text("Quoted text")])])
```

## Parsing and stringifying

### parseMarkdown

Parse a markdown string into an mdast AST.

```typescript
const ast = parseMarkdown("**Hello** world");
```

### stringifyMarkdown

Convert an mdast AST back to a markdown string.

```typescript
const md = stringifyMarkdown(ast); // "**Hello** world"
```

### toPlainText

Strip all formatting and return plain text.

```typescript
const plain = toPlainText(ast); // "Hello world"
```

### markdownToPlainText

Shorthand for parsing markdown and extracting plain text.

```typescript
const plain = markdownToPlainText("**Hello** world"); // "Hello world"
```

## AST utilities

### walkAst

Transform an AST by visiting each node. Return a new value to replace the node, or `undefined` to keep it unchanged.

```typescript
const transformed = walkAst(ast, (node) => {
  if (isStrongNode(node)) {
    return emphasis(getNodeChildren(node));
  }
  return undefined;
});
```

### Type guards

Functions for checking node types:

| Guard | Matches |
|-------|---------|
| `isTextNode(node)` | Plain text |
| `isParagraphNode(node)` | Paragraph |
| `isStrongNode(node)` | Bold |
| `isEmphasisNode(node)` | Italic |
| `isDeleteNode(node)` | Strikethrough |
| `isInlineCodeNode(node)` | Inline code |
| `isCodeNode(node)` | Code block |
| `isLinkNode(node)` | Link |
| `isBlockquoteNode(node)` | Blockquote |
| `isListNode(node)` | List |
| `isListItemNode(node)` | List item |
| `isTableNode(node)` | Table |
| `isTableRowNode(node)` | Table row |
| `isTableCellNode(node)` | Table cell |

### getNodeChildren / getNodeValue

Safely access node properties without type narrowing.

```typescript
const children = getNodeChildren(node); // Content[] | undefined
const value = getNodeValue(node);       // string | undefined
```

## Table utilities

### tableToAscii

Render an mdast `Table` node as a padded ASCII table string. Used by adapters that lack native table support (Slack, Google Chat, Discord, Telegram).

```typescript
import { parseMarkdown, tableToAscii, isTableNode } from "chat";

const ast = parseMarkdown("| Name | Role |\n|------|------|\n| Alice | Engineer |");
// Find the table node and convert it
```

Output:

```
Name  | Role
------|--------
Alice | Engineer
```

### tableElementToAscii

Render a table from headers and string row arrays as a padded ASCII table. Used for card `TableElement` fallback rendering.

```typescript
import { tableElementToAscii } from "chat";

const ascii = tableElementToAscii(
  ["Name", "Age", "Role"],
  [
    ["Alice", "30", "Engineer"],
    ["Bob", "25", "Designer"],
  ]
);
```

## Platform formatting

The SDK uses mdast as the canonical format and each adapter converts it to the platform's native syntax. You write standard markdown and the SDK handles the translation — but it helps to know how each platform renders common formatting.

| Feature | Slack | Teams | Google Chat |
|---------|-------|-------|-------------|
| Bold | `*text*` | `**text**` | `*text*` |
| Italic | `_text_` | `_text_` | `_text_` |
| Strikethrough | `~text~` | `~~text~~` | `~text~` |
| Code | `` `code` `` | `` `code` `` | `` `code` `` |
| Code blocks | ```` ``` ```` | ```` ``` ```` | ```` ``` ```` |
| Links | `<url\|text>` | `[text](url)` | `[text](url)` |
| Lists | Supported | Supported | Supported |
| Blockquotes | `>` | `>` | Simulated with `>` prefix |
| Tables | ASCII fallback | Native GFM | ASCII fallback |
| Mentions | `<@USER>` | `<at>name</at>` | `<users/{id}>` |

<Callout type="info">
You don't need to worry about these differences when using the SDK — the AST builders and `parseMarkdown` handle conversion automatically. This table is useful if you're working with `raw` platform payloads or debugging formatting issues.
</Callout>
