<Message />

A composable AI message UI for web and mobile, with content, actions, markdown response rendering, and branch navigation for alternate generations.

<Message /> is the foundation of the conversation UI in the AI starter. It is not only a message bubble, but a small family of components for laying out user and assistant messages, rendering rich responses, attaching actions, and handling response branches.

Web

The web version is the more feature-rich implementation. It supports user-versus-assistant layout treatment, hover-revealed actions, rich markdown rendering through Streamdown, and a compact branch selector for alternate responses.

Web message demo

Mobile

The mobile version keeps the same overall structure, but adapts it to a native layout with touch-friendly spacing and a lighter response renderer. It still supports actions and branch navigation, but without the hover-based affordances from the web version.

Mobile message demo

Blocks

The message system is intentionally composable. Most conversation UIs only need a few of these pieces, but the family gives you room to build from a simple bubble up to a more advanced assistant surface.

ComponentRole
MessageRoot wrapper that sets role-aware layout
MessageContentMain visual body of the message
MessageActionsAction row below or beside the message
MessageActionReusable action button primitive
MessageResponseRich response renderer for assistant output
MessageBranch*Components for alternate response navigation

The most important idea is that the root Message sets the role context, and the rest of the family adapts to that context rather than requiring you to pass the same role props over and over again.

Usage

The common pattern is a role-aware root message, a content section, and then optional actions. Assistant messages usually include MessageResponse, while user messages often render plain text or attachments inside MessageContent.

The web version works especially well when assistant output includes formatted markdown, code, math, or diagrams. The most relevant props are the from role on Message, regular layout props on MessageContent, button props on MessageAction, and Streamdown props on MessageResponse.

import {
  Message,
  MessageAction,
  MessageActions,
  MessageContent,
  MessageResponse,
} from "@workspace/ui-web/ai-elements/message";
import { Icons } from "@workspace/ui-web/icons";

export function AssistantMessage() {
  return (
    <Message from="assistant">
      <MessageContent>
        <MessageResponse>
          {
            "## Plan\n\nHere is a concise answer with **formatting** and `code`."
          }
        </MessageResponse>
      </MessageContent>

      <MessageActions>
        <MessageAction tooltip="Copy response">
          <Icons.Copy className="size-4" />
        </MessageAction>
      </MessageActions>
    </Message>
  );
}

Assistant and user roles

The message family changes its layout depending on the role. That makes user and assistant messages feel related, but not identical.

RoleTreatment
UserRight-aligned, bubble-like surface
AssistantLeft-aligned, more open content layout

That difference is subtle, but important. It lets rich assistant output breathe while still making user messages feel compact and clearly authored.

Response rendering

MessageResponse is one of the most useful pieces in the assistant side of the message family. It gives rich text output a dedicated renderer instead of pushing raw markdown handling into the surrounding conversation code.

PlatformRendererNotes
WebStreamdownSupports richer formatting, including code, math, mermaid, and CJK plugins
Mobilereact-native-enriched-markdownBetter suited to compact native rendering and scrolling

This is one of the reasons the message family is more than layout. It also standardizes how assistant output is actually presented.

Message branches

Both platforms support a branch-navigation model for alternate assistant responses. That is useful when the product allows regeneration or multiple candidate answers.

ComponentPurpose
MessageBranchHolds branch state
MessageBranchContentRenders the active branch
MessageBranchSelectorWraps the navigation controls
MessageBranchPrevious / MessageBranchNextMove between branches
MessageBranchPageShows the current branch index

The branch API is intentionally separate from the base Message so you only pay for that complexity when the product actually needs it.

Platform differences

The structure is shared, but the behavior still respects the platform.

AreaWebMobile
Action visibilityHover and focus revealTouch-first, always available in layout
Response renderingStreamdownNative markdown component
Root layoutdiv-based with role-specific utility classesAnimated.View with native layout transitions
Branch selector feelCompact desktop control groupNative button row

That balance keeps the component family consistent without making either platform feel awkwardly ported.

In the starter

The message family is where many of the other AI UI components come together. Attachments, tools, reasoning traces, context displays, and feedback actions often live inside or around a message.

That is why this page matters. If PromptInput starts the interaction, Message is where the result actually becomes visible to the user.

The message surface is usually composed with several other AI primitives. These are the most relevant companion pages in the docs set.

How is this guide?

Last updated on

On this page

Make AI your edge, not replacement.Get TurboStarter AI