Skip to content

feat: render GitHub-flavored markdown in chat messages - #39

Open
blaab2 wants to merge 1 commit into
VapiAI:mainfrom
blaab2:feat/gfm-markdown
Open

blaab2 wants to merge 1 commit into
VapiAI:mainfrom
blaab2:feat/gfm-markdown

Conversation

@blaab2

@blaab2 blaab2 commented Sep 25, 2026

Copy link
Copy Markdown

Problem

Chat messages go through react-markdown, but without any remark plugins, so only CommonMark renders. LLM assistants very often answer with GFM tables (price or option comparisons, for instance), and those currently show up in the bubble as raw | … | … | text. Strikethrough, autolinked bare URLs and task lists have the same problem.

Change

  • Add remark-gfm (^4, the line that matches react-markdown ^10) and pass it as remarkPlugins in MarkdownMessage (src/components/widget/conversation/Message.tsx).
  • Styling for the new elements, following the existing Tailwind idiom there:
    • table is wrapped in an overflow-x-auto div, because the bubble is capped at max-w-xs and wide tables would otherwise overflow the widget. Cells are text-xs with border-current, so they work in light and dark themes; header cells get the same bg-black bg-opacity-10 tint that code blocks use. Column alignment from :---: is kept, because the style react-markdown sets is passed through.
    • Cells need an explicit border-solid, because the widget's CSS reset sets no default border style (so border alone renders nothing).
    • Task-list checkboxes opt back into appearance-auto, because the reset's appearance: none on inputs would otherwise make them invisible.
    • del → line-through.
  • README: the feature bullet now mentions GFM.

Plain-CommonMark messages render exactly as before.

Tests

The existing embed specs never produce a message (that would need a live assistant), so there's no Playwright coverage for message rendering to extend. I checked it in a local harness that renders ConversationMessage with a 5-column table, strikethrough, a bare URL and a task list: all of them render, and the table scrolls horizontally inside a 384px widget.

npm run lint, npm run type-check, npm run format:check, npm run build, npm run build:widget and npm run test:ci all pass.

Related: #38 (localizable labels) — independent of this one; both apply cleanly on main.

🤖 Generated with Claude Code

Assistants routinely answer with GFM tables (e.g. price or option
comparisons), which CommonMark alone leaves as raw pipe characters in the
message bubble. Enable remark-gfm so tables, strikethrough, autolinks and
task lists render.

Tables sit in an overflow-x-auto wrapper because the bubble is capped at
max-w-xs; cells use border-solid explicitly because the widget's CSS reset
does not set a default border style, and task-list checkboxes opt back into
appearance-auto because the reset strips input appearance.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
blaab2 added a commit to blaab2/client-sdk-react that referenced this pull request Sep 25, 2026
Adds the chat-end-message attribute mapping (VapiAI#40)
on top of VapiAI#38 and VapiAI#39; dist/ rebuilt and committed as before.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant