Markdown

Streaming-safe markdown renderer wrapping Vercel's streamdown. Handles partial input mid-stream without throwing.

Streamed assistant turn

Setting up Tabs

Tabs is a Radix primitive — it ships keyboard navigation and roving tabindex out of the box. Wire it like this:

  • Wrap the trigger row in TabsList.
  • Each trigger declares the value it activates.
  • Pair each trigger with a matching TabsContent.
<Tabs defaultValue="overview">
  <TabsList>
    <TabsTrigger value="overview">Overview</TabsTrigger>
    <TabsTrigger value="usage">Usage</TabsTrigger>
  </TabsList>
  <TabsContent value="overview">…</TabsContent>
  <TabsContent value="usage">…</TabsContent>
</Tabs>

Always pass an aria-label on the root if the surrounding heading isn't tied via aria-labelledby.

Inline reply

Yes — useFormState is stable in React 19 and is the right hook for progressively-enhanced form actions.

Installation

pnpm
pnpm dlx @hex-core/cli add markdown

Custom rendering: drop down to Streamdown

For per-element overrides, use streamdown directly with our CodeBlock primitive.

tsx
import { Streamdown } from "streamdown";
import { CodeBlock } from "@hex-core/components";

<Streamdown components={{ pre: ({ children }) => <CodeBlock code={extractCode(children)} /> }}>
  {markdown}
</Streamdown>

API Reference

PropTypeDefaultDescription
childrenrequired
stringRaw markdown. May be a partial chunk during streaming.
className
stringAdditional CSS classes on the root element.

AI Guidance

When to use

Render any markdown content from an LLM — assistant turns, system messages with formatting, RAG citations with inline links. Required for streaming because raw markdown parsers throw on unfinished input.

When not to use

Don't use for plain text without formatting (just render the string). Don't bypass it for streamed content — partial input WILL break a non-streaming parser.

Common mistakes

  • Passing JSX children instead of a markdown string — Markdown only accepts strings
  • Trying to override per-element renderers via Markdown — drop down to `Streamdown` directly for that (we keep our public surface minimal so the DTS bundle doesn't drag in shiki's giant language union)
  • Forgetting Tailwind Typography (`prose`) classes are required to style the output

Accessibility

Inherits semantics from streamdown: real headings, lists, links. Verify Tailwind Typography (prose) is enabled in your CSS — without it, output renders unstyled.

Related components

Token budget: 280

Verified against @hex-core/components@1.12.0