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
npx shadcn add https://raw.githubusercontent.com/levi-putna/elements/main/registry/message/registry.jsonRequired: globals.css
Add this import to your globals.css so Streamdown code block styles are included in the Tailwind build.
/* Add to globals.css: required for MessageResponse code block styles */
@source "../node_modules/streamdown/dist/*.js";Usage
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
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.
The annual general meeting is scheduled for 15 August.
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.
Managed by Jane Smith at . Part of .
// 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.
// 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
| Prop | Type | Default | Description |
|---|---|---|---|
| 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
| Prop | Type | Default | Description |
|---|---|---|---|
| children | string | - | The markdown content to render. Supports GFM, code blocks with syntax highlighting, math (KaTeX), mermaid diagrams, and custom entity tags. |
| isAnimating | boolean | false | Pass true while status is "streaming" to enable streaming-optimised rendering. |
| parseIncompleteMarkdown | boolean | true | Enables graceful rendering of partial markdown during streaming. |
MessageAction Props
| Prop | Type | Default | Description |
|---|---|---|---|
| tooltip | string | - | Tooltip label shown on hover. |
| label | string | - | Screen reader label. Falls back to tooltip if not provided. |
| variant | string | "ghost" | Button variant. |
| size | string | "icon-sm" | Button size. |