Export menu
Export or share a conversation: copy as Markdown, download Markdown or JSON, print or save as PDF, and copy a share link with an async success state. Comes with chatcn-export, the helpers that turn ChatcnMessage[] into Markdown, JSON and print HTML.
On this page
Installation
Usage
import { ExportMenu } from "@/components/ui/chatcn/export-menu"
<ExportMenu
messages={messages}
title={chat.title}
onCreateLink={async () => (await createShareLink(chat.id)).url}
/>Copy actions confirm inside the menu (Copied, Link copied) and close 900 ms later. Creating a link shows a spinner in the item until the promise resolves; a failure stays open and says Link failed, try again. Downloads and print close at once, because the browser takes over. Print renders only the conversation, from a hidden frame, so the app around it never ends up in the PDF.
The helpers
import { toJSON, toMarkdown, toPrintHtml, downloadText, exportFilename } from "@/lib/chatcn-export"
const md = toMarkdown(messages, { title, includeReasoning: false, tools: "summary" })
downloadText(exportFilename(title, "md"), md, "text/markdown")Markdown puts each author in bold, separates turns with a rule, and turns each tool call into one line such as Used edit_file on src/queue/webhooks.ts, done. Reasoning is left out unless asked. JSON is lossless, so the file can be loaded back as messages. Unknown parts are skipped, never fatal.
Examples
Export menu
Markdown output
States
Props
| Prop | Type | Notes |
|---|---|---|
messages | ChatcnMessage[] | () => ChatcnMessage[] | Required. A function runs only on export |
title | string | Heading, print title and file names |
formats | ExportFormat[] | Which actions, in order. Defaults to all five |
link | string | A ready share link |
onCreateLink | () => Promise<string> | string | Creates a link on demand |
includeReasoning, defaultIncludeReasoning, onIncludeReasoningChange | boolean | Controlled or uncontrolled |
reasoningToggle | boolean | Show Include reasoning. Defaults to on when any reasoning exists |
options | ChatcnExportOptions | tools, includeSystem, roleLabels |
onPrint | (html: string) => void | Replace the default print |
onExport | (format, content) => void | After every export, with what was produced |
trigger | ReactElement | Your own trigger, such as an icon button |
align, side | Menu placement. Defaults to end and bottom | |
disabled | boolean | Also disabled when messages is empty |
Keyboard
| Key | Action |
|---|---|
Enter, Space, ArrowDown | Open the menu from the trigger |
ArrowDown, ArrowUp | Move between actions. Highlight is instant |
Enter | Run the action |
Esc | Close and return focus to the trigger |
Accessibility
- A Base UI menu: roving focus, typeahead and focus return. Copy results and failures are announced through a polite live region.
- Success is green with a check and a new label, failure red with an alert icon and a new label, so color is never the only signal.
- Items are 44 px tall on touch screens.
Motion
- The menu opens from its trigger in 180 ms and closes in 140 ms. Opened from the keyboard, it skips the animation.
- Item icons swap to a spinner, check or alert with the 150 ms blur crossfade, instantly when chosen from the keyboard.