Looking for the chatbot template? It's now here.

Markdown

AST builder functions and utilities for programmatic message formatting.

The SDK uses mdast (Markdown AST) as the canonical format for message formatting. Each adapter converts the AST to the platform's native format.

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

Node builders

root

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

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

Prop

Type

paragraph

A paragraph block.

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

text

Plain text node.

text("Hello, world!")

strong

Bold text.

strong([text("important")])

emphasis

Italic text.

emphasis([text("emphasized")])

strikethrough

Strikethrough text.

strikethrough([text("removed")])

inlineCode

Inline code span.

inlineCode("const x = 1")

codeBlock

Fenced code block with optional language.

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

Prop

Type

Hyperlink.

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

Prop

Type

blockquote

Block quotation.

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

Parsing and stringifying

parseMarkdown

Parse a markdown string into an mdast AST.

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

stringifyMarkdown

Convert an mdast AST back to a markdown string.

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

toPlainText

Strip all formatting and return plain text.

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

markdownToPlainText

Shorthand for parsing markdown and extracting plain text.

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.

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

Type guards

Functions for checking node types:

GuardMatches
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

getNodeChildren / getNodeValue

Safely access node properties without type narrowing.

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

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.

FeatureSlackTeamsGoogle 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)
ListsSupportedSupportedSupported
Blockquotes>>Simulated with > prefix
Mentions<@USER><at>name</at><users/{id}>

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.