f-ui
Components

Message

Chat row layout with align, avatar, header, content, footer, and group parts.

Plus Registry

This component ships from registry.plus.json, not the public registry.json. Set up @f-ui-plus on the Installation page, then install @f-ui-plus/message.

Tracks Shadcn

Layout primitives track shadcn ui/message. The Plus path @f-ui-plus/message re-exports those parts for installers.

Message is the chat row — alignment, optional avatar, and content slots. It does not own markdown, bubbles, or scroll. Compose Bubble for user chips and Markdown Renderer for assistant text; wrap each row in Message Scroller MessageScrollerItem inside a transcript.

When To Use

  • Lay out a single turn with start (assistant) or end (user) alignment.
  • You need header / footer metadata (author, timestamp) around the body.
  • Group consecutive parts under one row with MessageGroup.
  • Prefer Marker for date separators and “Thinking…” status — not Message.

Features

AreaBehavior
Alignstart default; end applies flex-row-reverse (DOM order stays Avatar then Content)
AvatarOptional via MessageAvatar — omit the slot when you do not need an avatar
ContentMessageContent stacks header, body, footer
GroupMessageGroup for stacked parts in one turn

Installing

Configure @f-ui-plus and FUI_PLUS_REGISTRY_TOKEN as in Installation — Plus Registry.

FUI_PLUS_REGISTRY_TOKEN=xxx pnpm dlx shadcn@latest add @f-ui-plus/message
FUI_PLUS_REGISTRY_TOKEN=xxx npx shadcn@latest add @f-ui-plus/message
FUI_PLUS_REGISTRY_TOKEN=xxx yarn dlx shadcn@latest add @f-ui-plus/message
FUI_PLUS_REGISTRY_TOKEN=xxx bun x shadcn@latest add @f-ui-plus/message

registryDependencies: bare shadcn message (CLI resolves against the default registry). No extra runtime packages.

Usage

import { Message, MessageContent } from "@/components/f-ui/message/message";
import { Bubble, BubbleContent } from "@/components/f-ui/bubble/bubble";

<Message align="end">
  <MessageContent>
    <Bubble>
      <BubbleContent>
        <p className="whitespace-pre-wrap">Hi</p>
      </BubbleContent>
    </Bubble>
  </MessageContent>
</Message>

Examples

Align Start and End

Assistant rows use align="start"; user rows use align="end" with a Bubble. No avatar — content only.

Assistant

Aligned start — typical assistant turn.

Just now
You

Aligned end — user prompt in a bubble.

"use client";

import { Bubble, BubbleContent } from "@/components/f-ui/bubble/bubble";
import {
  Message,
  MessageContent,
  MessageFooter,
  MessageHeader,
} from "@/components/f-ui/message/message";

export function MessageDemo() {
  return (
    <div className="flex flex-col gap-6">
      <Message align="start">
        <MessageContent>
          <MessageHeader>Assistant</MessageHeader>
          <p className="text-sm">Aligned start — typical assistant turn.</p>
          <MessageFooter>Just now</MessageFooter>
        </MessageContent>
      </Message>
      <Message align="end">
        <MessageContent>
          <MessageHeader>You</MessageHeader>
          <Bubble>
            <BubbleContent>
              <p className="whitespace-pre-wrap">Aligned end — user prompt in a bubble.</p>
            </BubbleContent>
          </Bubble>
        </MessageContent>
      </Message>
    </div>
  );
}

With Avatar

Optional MessageAvatar before MessageContent for both aligns. On end, flex-row-reverse keeps the avatar visually trailing while DOM order stays Avatar then Content.

AI
Assistant

Optional avatar on start rows.

Just now
You

Avatar stays at the end via row-reverse.

"use client";

import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { Bubble, BubbleContent } from "@/components/f-ui/bubble/bubble";
import {
  Message,
  MessageAvatar,
  MessageContent,
  MessageFooter,
  MessageHeader,
} from "@/components/f-ui/message/message";

export function MessageAvatarDemo() {
  return (
    <div className="flex flex-col gap-6">
      <Message align="start">
        <MessageAvatar>
          <Avatar className="size-8">
            <AvatarFallback>AI</AvatarFallback>
          </Avatar>
        </MessageAvatar>
        <MessageContent>
          <MessageHeader>Assistant</MessageHeader>
          <p className="text-sm">Optional avatar on start rows.</p>
          <MessageFooter>Just now</MessageFooter>
        </MessageContent>
      </Message>
      <Message align="end">
        <MessageAvatar>
          <Avatar className="size-8">
            <AvatarFallback>You</AvatarFallback>
          </Avatar>
        </MessageAvatar>
        <MessageContent>
          <Bubble>
            <BubbleContent>
              <p className="whitespace-pre-wrap">
                Avatar stays at the end via row-reverse.
              </p>
            </BubbleContent>
          </Bubble>
        </MessageContent>
      </Message>
    </div>
  );
}

Composition

Message
├── MessageAvatar?
└── MessageContent
    ├── MessageHeader?
    ├── (Bubble | MarkdownRenderer | host children)
    └── MessageFooter?

MessageGroup may wrap stacked content inside MessageContent.

API Reference

Props

PropTypeDefaultDescription
align"start" | "end""start"Row direction; end uses flex-row-reverse.
classNamestringMerged onto the row root.
childrenReactNodeAvatar + content parts (Avatar then Content in DOM).

Slots

Parts: Message, MessageAvatar, MessageContent, MessageHeader, MessageFooter, MessageGroup. Style via each part’s className.

On this page