Elements

Components / AI

Message

Composable AI chat message components with streaming markdown, syntax-highlighted code blocks, math equations, mermaid diagrams, and custom entity tags for people, locations, and strata schemes. Extends ai-elements Message.

Installation

bash
npx shadcn add https://raw.githubusercontent.com/levi-putna/elements/main/registry/message/registry.json

Required: globals.css

Add this import to your globals.css so Streamdown code block styles are included in the Tailwind build.

css
/* Add to globals.css: required for MessageResponse code block styles */
@source "../node_modules/streamdown/dist/*.js";

Usage

tsx
import { Message, MessageContent, MessageResponse } from "@/components/ui/message"

export function ChatMessage({ message }) {
  return (
    <Message from={message.role}>
      <MessageContent>
        <MessageResponse isAnimating={false}>
          {message.content}
        </MessageResponse>
      </MessageContent>
    </Message>
  )
}

Examples

User and assistant messages

Preview
What strata fees apply to SP12345?

The quarterly levy for SP12345 is $842. This covers building insurance, common area maintenance, and the sinking fund contribution.

With action toolbar

Use MessageToolbar with MessageActions to add copy, retry, and other actions beneath a message.

Preview

The annual general meeting is scheduled for 15 August.

tsx
import {
  Message,
  MessageContent,
  MessageResponse,
  MessageToolbar,
  MessageActions,
  MessageAction,
} from "@/components/ui/message"
import { CopyIcon, RotateCcwIcon } from "lucide-react"

export function AssistantMessage({ message, onRetry }) {
  return (
    <Message from="assistant">
      <MessageContent>
        <MessageResponse>{message.content}</MessageResponse>
      </MessageContent>
      <MessageToolbar>
        <MessageActions>
          <MessageAction
            tooltip="Copy"
            onClick={() => navigator.clipboard.writeText(message.content)}
          >
            <CopyIcon />
          </MessageAction>
          <MessageAction tooltip="Retry" onClick={onRetry}>
            <RotateCcwIcon />
          </MessageAction>
        </MessageActions>
      </MessageToolbar>
    </Message>
  )
}

Custom entity tags

The AI can include structured entity references in its markdown. They render as styled inline badges without any extra parsing on your side.

Preview

Managed by Jane Smith at . Part of .

tsx
// The AI response markdown can include custom entity tags:
// <person name="Jane Smith" id="u_123">Jane Smith</person>
// <location address="42 Park Rd" suburb="Bondi" state="NSW" />
// <strata-scheme plan="SP12345" name="Sunrise Apartments" />

// MessageResponse will render these as styled inline badges automatically.
// No extra setup needed: the plugins are built in.

const exampleContent = `
The lot is managed by <person name="Jane Smith" id="u_123">Jane Smith</person>
and located at <location address="42 Park Rd" suburb="Bondi" state="NSW" />.
It belongs to <strata-scheme plan="SP12345" name="Sunrise Apartments" />.
`;

<MessageResponse>{exampleContent}</MessageResponse>

Adding a new entity type

Add a plugin object to streamdownPlugins in registry/message/message.tsx.

tsx
// To add a new entity type, open registry/message/message.tsx
// and add a plugin to the streamdownPlugins object:

const myPlugin = {
  name: "document",           // matches the HTML tag name
  render: ({ title, id, children }) => (
    <span
      className="inline-flex items-center gap-1 rounded-sm bg-purple-50 px-1.5 py-0.5 text-purple-700 text-xs font-medium ring-1 ring-purple-200"
      data-entity="document"
      data-id={id}
    >
      {children ?? title}
    </span>
  ),
};

const streamdownPlugins = {
  cjk, code, math, mermaid,
  person: personPlugin,
  location: locationPlugin,
  "strata-scheme": strataSchemePlugin,
  document: myPlugin,          // ← add here
};

Message Props

PropTypeDefaultDescription
from"user" | "assistant" | "system"-The message role. Controls alignment and styling: user messages are right-aligned with secondary background, assistant messages are left-aligned full-width.

MessageResponse Props

PropTypeDefaultDescription
childrenstring-The markdown content to render. Supports GFM, code blocks with syntax highlighting, math (KaTeX), mermaid diagrams, and custom entity tags.
isAnimatingbooleanfalsePass true while status is "streaming" to enable streaming-optimised rendering.
parseIncompleteMarkdownbooleantrueEnables graceful rendering of partial markdown during streaming.

MessageAction Props

PropTypeDefaultDescription
tooltipstring-Tooltip label shown on hover.
labelstring-Screen reader label. Falls back to tooltip if not provided.
variantstring"ghost"Button variant.
sizestring"icon-sm"Button size.