codefast/ui

Command Palette

Search for a command to run...

Source
Display

Message

Chat message row pairing an avatar with a content column; mirrors for the current author.

Examples

Thread

Compose MessageGroup with alternating Message rows. The avatar, header, and footer are optional per row.

AD
Ada Lovelace
Morning! The new registry docs are live — want to review before we ship?
Yes! Joining now.
9:41 AM · Read
AD
Great — starting with the chat components.
9:42 AM
62 lines
import { Avatar, AvatarFallback, AvatarImage } from "@codefast/ui/avatar";
import { Bubble, BubbleContent, BubbleReactions } from "@codefast/ui/bubble";
import {
  Message,
  MessageAvatar,
  MessageContent,
  MessageFooter,
  MessageGroup,
  MessageHeader,
} from "@codefast/ui/message";

export function MessageThread() {
  return (
    <MessageGroup className="w-full max-w-sm">
      <Message>
        <MessageAvatar>
          <Avatar size="sm">
            <AvatarImage
              alt="@ada"
              src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=128&h=128&fit=crop&q=80"
            />
            <AvatarFallback>AD</AvatarFallback>
          </Avatar>
        </MessageAvatar>
        <MessageContent>
          <MessageHeader>Ada Lovelace</MessageHeader>
          <Bubble variant="muted">
            <BubbleContent>Morning! The new registry docs are live — want to review before we ship?</BubbleContent>
          </Bubble>
        </MessageContent>
      </Message>
      <Message align="end">
        <MessageContent>
          <Bubble align="end">
            <BubbleContent>Yes! Joining now.</BubbleContent>
            <BubbleReactions aria-label="Reaction: thumbs up" role="img">
              👍
            </BubbleReactions>
          </Bubble>
          <MessageFooter>9:41 AM · Read</MessageFooter>
        </MessageContent>
      </Message>
      <Message>
        <MessageAvatar>
          <Avatar size="sm">
            <AvatarImage
              alt="@ada"
              src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=128&h=128&fit=crop&q=80"
            />
            <AvatarFallback>AD</AvatarFallback>
          </Avatar>
        </MessageAvatar>
        <MessageContent>
          <Bubble variant="muted">
            <BubbleContent>Great — starting with the chat components.</BubbleContent>
          </Bubble>
          <MessageFooter>9:42 AM</MessageFooter>
        </MessageContent>
      </Message>
    </MessageGroup>
  );
}

Avatar

Attach an author avatar with MessageAvatar; consecutive same-author rows can drop it.

R
The build failed during dependency installation.
G
Can you share the exact error?
R
Here’s the error from the logs
Something went wrong with the build. The libraries are not installed correctly. Try running the build again.
66 lines
import { Avatar, AvatarFallback, AvatarImage } from "@codefast/ui/avatar";
import { Bubble, BubbleContent, BubbleGroup } from "@codefast/ui/bubble";
import { Message, MessageAvatar, MessageContent } from "@codefast/ui/message";

export function MessageAvatarDemo() {
  return (
    <div className="flex w-full max-w-sm flex-col gap-6">
      <Message>
        <MessageAvatar>
          <Avatar>
            <AvatarImage
              alt="@rocky"
              src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=128&h=128&fit=crop&q=80"
            />
            <AvatarFallback>R</AvatarFallback>
          </Avatar>
        </MessageAvatar>
        <MessageContent>
          <Bubble variant="muted">
            <BubbleContent>The build failed during dependency installation.</BubbleContent>
          </Bubble>
        </MessageContent>
      </Message>
      <Message align="end">
        <MessageAvatar>
          <Avatar>
            <AvatarImage
              alt="@grace"
              src="https://images.unsplash.com/photo-1544005313-94ddf0286df2?w=128&h=128&fit=crop&q=80"
            />
            <AvatarFallback>G</AvatarFallback>
          </Avatar>
        </MessageAvatar>
        <MessageContent>
          <Bubble>
            <BubbleContent>Can you share the exact error?</BubbleContent>
          </Bubble>
        </MessageContent>
      </Message>
      <Message>
        <MessageAvatar>
          <Avatar>
            <AvatarImage
              alt="@rocky"
              src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=128&h=128&fit=crop&q=80"
            />
            <AvatarFallback>R</AvatarFallback>
          </Avatar>
        </MessageAvatar>
        <MessageContent>
          <BubbleGroup>
            <Bubble variant="muted">
              <BubbleContent>Here’s the error from the logs</BubbleContent>
            </Bubble>
            <Bubble variant="muted">
              <BubbleContent>
                Something went wrong with the build. The libraries are not installed correctly. Try running the build
                again.
              </BubbleContent>
            </Bubble>
          </BubbleGroup>
        </MessageContent>
      </Message>
    </div>
  );
}

Group

MessageGroup stacks related rows; an empty MessageAvatar keeps content aligned without a picture.

I checked the registry addresses.
CN
The component and example JSON now live under the UI registry.
36 lines
import { Avatar, AvatarFallback, AvatarImage } from "@codefast/ui/avatar";
import { Bubble, BubbleContent } from "@codefast/ui/bubble";
import { Message, MessageAvatar, MessageContent, MessageGroup } from "@codefast/ui/message";

export function MessageGroupDemo() {
  return (
    <div className="flex w-full max-w-sm flex-col gap-6">
      <MessageGroup>
        <Message>
          <MessageAvatar />
          <MessageContent>
            <Bubble variant="muted">
              <BubbleContent>I checked the registry addresses.</BubbleContent>
            </Bubble>
          </MessageContent>
        </Message>
        <Message>
          <MessageAvatar>
            <Avatar>
              <AvatarImage
                alt="@rocky"
                src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=128&h=128&fit=crop&q=80"
              />
              <AvatarFallback>CN</AvatarFallback>
            </Avatar>
          </MessageAvatar>
          <MessageContent>
            <Bubble variant="muted">
              <BubbleContent>The component and example JSON now live under the UI registry.</BubbleContent>
            </Bubble>
          </MessageContent>
        </Message>
      </MessageGroup>
    </div>
  );
}

Actions

Put per-message controls (copy, react, retry) in MessageFooter; it aligns with the row.

The install failure is coming from the workspace package.
Okay drop me a link. Taking a look…
Failed to send
42 lines
import { Bubble, BubbleContent } from "@codefast/ui/bubble";
import { Button } from "@codefast/ui/button";
import { Message, MessageContent, MessageFooter } from "@codefast/ui/message";
import { CopyIcon, RefreshCcwIcon, ThumbsDownIcon, ThumbsUpIcon } from "lucide-react";

export function MessageActions() {
  return (
    <div className="flex w-full max-w-sm flex-col gap-6">
      <Message>
        <MessageContent>
          <Bubble variant="muted">
            <BubbleContent>The install failure is coming from the workspace package.</BubbleContent>
          </Bubble>
          <MessageFooter>
            <Button aria-label="Copy" size="icon-xs" title="Copy" variant="ghost">
              <CopyIcon />
            </Button>
            <Button aria-label="Like" size="icon-xs" title="Like" variant="ghost">
              <ThumbsUpIcon />
            </Button>
            <Button aria-label="Dislike" size="icon-xs" title="Dislike" variant="ghost">
              <ThumbsDownIcon />
            </Button>
          </MessageFooter>
        </MessageContent>
      </Message>
      <Message align="end">
        <MessageContent>
          <Bubble align="end">
            <BubbleContent>Okay drop me a link. Taking a look…</BubbleContent>
          </Bubble>
          <MessageFooter className="gap-2">
            <span className="font-normal text-destructive">Failed to send</span>
            <Button aria-label="Retry" size="icon-xs" title="Retry" variant="ghost">
              <RefreshCcwIcon />
            </Button>
          </MessageFooter>
        </MessageContent>
      </Message>
    </div>
  );
}

With attachments

Compose Attachment inside MessageContent to send and receive files alongside bubbles.

Workspace
Here’s the image. Can you add it to the PDF? Use it for the cover page.
Done. Here’s the PDF with the image added as the cover page.
sales-dashboard.pdfPDF · 2.4 MB
Thanks. Looks good.
65 lines
import {
  Attachment,
  AttachmentAction,
  AttachmentActions,
  AttachmentContent,
  AttachmentDescription,
  AttachmentMedia,
  AttachmentTitle,
} from "@codefast/ui/attachment";
import { Bubble, BubbleContent } from "@codefast/ui/bubble";
import { Message, MessageContent } from "@codefast/ui/message";
import { Image } from "@unpic/react";
import { DownloadIcon, FileTextIcon } from "lucide-react";

export function MessageAttachment() {
  return (
    <div className="flex w-full max-w-sm flex-col gap-6">
      <Message align="end">
        <MessageContent>
          <Attachment orientation="vertical">
            <AttachmentMedia variant="image">
              <Image
                alt="Workspace"
                className="size-full object-cover"
                layout="fullWidth"
                src="https://images.unsplash.com/photo-1497366754035-f200968a6e72?w=600&auto=format&fit=crop&q=80"
              />
            </AttachmentMedia>
          </Attachment>
          <Bubble>
            <BubbleContent>Here’s the image. Can you add it to the PDF? Use it for the cover page.</BubbleContent>
          </Bubble>
        </MessageContent>
      </Message>
      <Message>
        <MessageContent>
          <Bubble variant="muted">
            <BubbleContent>Done. Here’s the PDF with the image added as the cover page.</BubbleContent>
          </Bubble>
          <Attachment>
            <AttachmentMedia>
              <FileTextIcon />
            </AttachmentMedia>
            <AttachmentContent>
              <AttachmentTitle>sales-dashboard.pdf</AttachmentTitle>
              <AttachmentDescription>PDF · 2.4 MB</AttachmentDescription>
            </AttachmentContent>
            <AttachmentActions>
              <AttachmentAction aria-label="Download" size="icon-sm" title="Download" type="button" variant="secondary">
                <DownloadIcon />
              </AttachmentAction>
            </AttachmentActions>
          </Attachment>
        </MessageContent>
      </Message>
      <Message align="end">
        <MessageContent>
          <Bubble>
            <BubbleContent>Thanks. Looks good.</BubbleContent>
          </Bubble>
        </MessageContent>
      </Message>
    </div>
  );
}

Markdown

Render assistant text in a ghost bubble as plain paragraphs; keep user messages as plain text.

How do I render markdown in a message?

Here's how to render markdown in a message:

1. Render assistant text through Markdown. 2. Keep user messages as plain text. 3. Use a ghost bubble so the response is unframed.

37 lines
import { Bubble, BubbleContent } from "@codefast/ui/bubble";
import { Message, MessageContent } from "@codefast/ui/message";

const response = `Here's how to render markdown in a message:

1. Render assistant text through Markdown.
2. Keep user messages as plain text.
3. Use a ghost bubble so the response is unframed.`;

export function MessageMarkdown() {
  const paragraphs = response.split("\n\n");

  return (
    <div className="flex w-full max-w-sm flex-col gap-6">
      <Message align="end">
        <MessageContent>
          <Bubble>
            <BubbleContent>How do I render markdown in a message?</BubbleContent>
          </Bubble>
        </MessageContent>
      </Message>
      <Message>
        <MessageContent>
          <Bubble variant="ghost">
            <BubbleContent>
              {paragraphs.map((paragraph) => (
                <p key={paragraph} className="whitespace-pre-wrap">
                  {paragraph}
                </p>
              ))}
            </BubbleContent>
          </Bubble>
        </MessageContent>
      </Message>
    </div>
  );
}

Usage

The minimal import and composition — see Examples below for styled, real-world variants.

14 lines
import { Bubble, BubbleContent } from "@codefast/ui/bubble";
import { Message, MessageContent } from "@codefast/ui/message";

export function MessageUsage() {
  return (
    <Message>
      <MessageContent>
        <Bubble>
          <BubbleContent>Hey, how&apos;s it going?</BubbleContent>
        </Bubble>
      </MessageContent>
    </Message>
  );
}

Anatomy

How the parts nest — every slot the component exposes, in composition order.

MessageGroup
└── Message
├── MessageAvatar
└── MessageContent
├── MessageHeader
└── MessageFooter

Features

  • align="end" reverses the row (avatar/content order) for the current user's own messages — no manual flex-direction needed.
  • MessageAvatar lifts above MessageFooter automatically when a footer is present, so it doesn't collide with delivery-status text.
  • Designed to sit inside MessageScroller for long, keyboard- and screen-reader-navigable transcripts.

API reference

Props for each part of the component. All native element props are also forwarded.

Message

A single message row: avatar plus content column.

align"start" | "end"

Which author side the row belongs to; 'end' reverses the row direction.

Default"start"

MessageContent

Column holding the bubbles and metadata; end-aligned rows self-align their children.

childrenReactNode

Bubbles, MessageHeader, MessageFooter.

MessageAvatar

Optional author avatar; lifts above MessageFooter when a footer is present.

childrenReactNode

An Avatar element.

MessageHeader

Metadata row above the bubbles, e.g. author name and timestamp.

childrenReactNode

Header text such as name and time.

MessageFooter

Metadata row below the bubbles, e.g. delivery status and actions; aligns with the row.

childrenReactNode

Footer text or controls such as status and reaction buttons.

MessageGroup

Vertical stack of related messages.

childrenReactNode

One or more Message rows.

Accessibility

Built to be keyboard-navigable and screen-reader friendly out of the box.

  • Message is presentational; put author and time in MessageHeader/MessageFooter as real text, not color or side alone.
  • Row direction and spacing mirror automatically under a DirectionProvider (RTL).
  • For long feeds, render messages inside MessageScroller so keyboard and screen-reader users can navigate the transcript.

Guidelines

Conventions that keep usage consistent across an app.

Do

  • Use align='end' for the current user's messages and 'start' for others.
  • Attach avatars to incoming messages and drop them on consecutive same-author rows.

Don’t

  • Don’t convey the author with alignment alone — keep a visible name or avatar.
  • Don’t hard-code left/right; use align so the row mirrors in RTL.

Explore further

Ready to integrate?

Follow the Getting Started guide to install @codefast/ui, or browse the full component gallery.