• Blog
  • Docs
  • Pricing
  • We’re hiring!
Log inSign up
drewmcdonald

drewmcdonald

promptCompare

Public
Like
promptCompare
Home
Code
12
.claude
3
.playwright-mcp
1
.zed
1
backend
3
docs
5
frontend
4
shared
1
.gitignore
.mcp.json
.vtignore
CLAUDE.md
deno.json
Environment variables
2
Branches
1
Pull requests
Remixes
History
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Sign up now
Code
/
.claude
/
skills
/
ai-elements
/
references
/
message.md
Code
/
.claude
/
skills
/
ai-elements
/
references
/
message.md
Search
…
Viewing readonly version of main branch: v188
View latest version
message.md

Message

A comprehensive suite of components for displaying chat messages, including message rendering, branching, actions, and markdown responses.

The Message component suite provides a complete set of tools for building chat interfaces. It includes components for displaying messages from users and AI assistants, managing multiple response branches, adding action buttons, and rendering markdown content.

See scripts/message.tsx for this example.

Installation

npx ai-elements@latest add message

Features

  • Displays messages from both user and AI assistant with distinct styling and automatic alignment
  • Minimalist flat design with user messages in secondary background and assistant messages full-width
  • Response branching with navigation controls to switch between multiple AI response versions
  • Markdown rendering with GFM support (tables, task lists, strikethrough), math equations, and smart streaming
  • Action buttons for common operations (retry, like, dislike, copy, share) with tooltips and state management
  • File attachments display with support for images and generic files with preview and remove functionality
  • Code blocks with syntax highlighting and copy-to-clipboard functionality
  • Keyboard accessible with proper ARIA labels
  • Responsive design that adapts to different screen sizes
  • Seamless light/dark theme integration

Usage with AI SDK

Build a simple chat UI where the user can copy or regenerate the most recent message.

Add the following component to your frontend:

Create val
"use client"; import { useState } from "react"; import { MessageAction, MessageActions, } from "@/components/ai-elements/message"; import { Message, MessageContent } from "@/components/ai-elements/message"; import { Conversation, ConversationContent, ConversationScrollButton, } from "@/components/ai-elements/conversation"; import { Input, PromptInputSubmit, PromptInputTextarea, } from "@/components/ai-elements/prompt-input"; import { MessageResponse } from "@/components/ai-elements/message"; import { CopyIcon, RefreshCcwIcon } from "lucide-react"; import { useChat } from "@ai-sdk/react"; import { Fragment } from "react"; const ActionsDemo = () => { const [input, setInput] = useState(""); const { messages, sendMessage, status, regenerate } = useChat(); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (input.trim()) { sendMessage({ text: input }); setInput(""); } }; return ( <div className="max-w-4xl mx-auto p-6 relative size-full rounded-lg border h-[600px]"> <div className="flex flex-col h-full"> <Conversation> <ConversationContent> {messages.map((message, messageIndex) => ( <Fragment key={message.id}> {message.parts.map((part, i) => { switch (part.type) { case "text": const isLastMessage = messageIndex === messages.length - 1; return ( <Fragment key={`${message.id}-${i}`}> <Message from={message.role}> <MessageContent> <MessageResponse>{part.text}</MessageResponse> </MessageContent> </Message> {message.role === "assistant" && isLastMessage && ( <MessageActions> <MessageAction onClick={() => regenerate()} label="Retry" > <RefreshCcwIcon className="size-3" /> </MessageAction> <MessageAction onClick={() => navigator.clipboard.writeText(part.text)} label="Copy" > <CopyIcon className="size-3" /> </MessageAction> </MessageActions> )} </Fragment> ); default: return null; } })} </Fragment> ))} </ConversationContent> <ConversationScrollButton /> </Conversation> <Input onSubmit={handleSubmit} className="mt-4 w-full max-w-2xl mx-auto relative" > <PromptInputTextarea value={input} placeholder="Say something..." onChange={(e) => setInput(e.currentTarget.value)} className="pr-12" /> <PromptInputSubmit status={status === "streaming" ? "streaming" : "ready"} disabled={!input.trim()} className="absolute bottom-1 right-1" /> </Input> </div> </div> ); }; export default ActionsDemo;

Props

<Message />

PropTypeDefaultDescription
fromUIMessage[-The role of the message sender (
...propsReact.HTMLAttributes<HTMLDivElement>-Any other props are spread to the root div.

<MessageContent />

PropTypeDefaultDescription
...propsReact.HTMLAttributes<HTMLDivElement>-Any other props are spread to the content div.

<MessageResponse />

PropTypeDefaultDescription
childrenstring-The markdown content to render.
parseIncompleteMarkdownbooleantrueWhether to parse and fix incomplete markdown syntax (e.g., unclosed code blocks or lists).
classNamestring-CSS class names to apply to the wrapper div element.
componentsobject-Custom React components to use for rendering markdown elements (e.g., custom heading, paragraph, code block components).
allowedImagePrefixesstring[][Array of allowed URL prefixes for images. Use [
allowedLinkPrefixesstring[][Array of allowed URL prefixes for links. Use [
defaultOriginstring-Default origin to use for relative URLs in links and images.
rehypePluginsarray[rehypeKatex]Array of rehype plugins to use for processing HTML. Includes KaTeX for math rendering by default.
remarkPluginsarray[remarkGfm, remarkMath]Array of remark plugins to use for processing markdown. Includes GitHub Flavored Markdown and math support by default.
...propsReact.HTMLAttributes<HTMLDivElement>-Any other props are spread to the root div.

<MessageActions />

PropTypeDefaultDescription
...propsReact.HTMLAttributes<HTMLDivElement>-HTML attributes to spread to the root div.

<MessageAction />

PropTypeDefaultDescription
tooltipstring-Optional tooltip text shown on hover.
labelstring-Accessible label for screen readers. Also used as fallback if tooltip is not provided.
...propsReact.ComponentProps<typeof Button>-Any other props are spread to the underlying shadcn/ui Button component.

<MessageBranch />

PropTypeDefaultDescription
defaultBranchnumber0The index of the branch to show by default.
onBranchChange(branchIndex: number) => void-Callback fired when the branch changes.
...propsReact.HTMLAttributes<HTMLDivElement>-Any other props are spread to the root div.

<MessageBranchContent />

PropTypeDefaultDescription
...propsReact.HTMLAttributes<HTMLDivElement>-Any other props are spread to the root div.

<MessageBranchSelector />

PropTypeDefaultDescription
fromUIMessage[-Aligns the selector for user, assistant or system messages.
...propsReact.HTMLAttributes<HTMLDivElement>-Any other props are spread to the selector container.

<MessageBranchPrevious />

PropTypeDefaultDescription
...propsReact.ComponentProps<typeof Button>-Any other props are spread to the underlying shadcn/ui Button component.

<MessageBranchNext />

PropTypeDefaultDescription
...propsReact.ComponentProps<typeof Button>-Any other props are spread to the underlying shadcn/ui Button component.

<MessageBranchPage />

PropTypeDefaultDescription
...propsReact.HTMLAttributes<HTMLSpanElement>-Any other props are spread to the underlying span element.

<MessageAttachments />

A container component for displaying file attachments in a message. Automatically positions attachments at the end of the message with proper spacing and alignment.

PropTypeDefaultDescription
childrenReactNode-MessageAttachment components to render. Returns null if no children provided.
...propsReact.ComponentProps<-Any other props are spread to the root div.

Example:

Create val
<MessageAttachments className="mb-2"> {files.map((attachment) => ( <MessageAttachment data={attachment} key={attachment.url} /> ))} </MessageAttachments>;

<MessageAttachment />

Displays a single file attachment. Images are shown as thumbnails (96px × 96px) with rounded corners. Non-image files show a paperclip icon with the filename.

PropTypeDefaultDescription
dataFileUIPart-The file data to display. Must include url and mediaType.
onRemove() => void-Optional callback fired when the remove button is clicked. If provided, a remove button will appear on hover.
...propsReact.HTMLAttributes<HTMLDivElement>-Any other props are spread to the root div.

Example:

Create val
<MessageAttachment data={{ type: "file", url: "https://example.com/image.jpg", mediaType: "image/jpeg", filename: "image.jpg", }} onRemove={() => console.log("Remove clicked")} />;
FeaturesVersion controlCode intelligenceCLIMCP
Use cases
TeamsAI agentsSlackGTM
DocsShowcaseTemplatesNewestTrendingAPI examplesNPM packages
PricingNewsletterBlogAboutCareers
We’re hiring!
Brandhi@val.townStatus
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Open Source Pledge
Terms of usePrivacy policyAbuse contact
© 2026 Val Town, Inc.