Components
- Accordion
- Alert
- Alert Dialog
- Ask User Questions
- Aspect Ratio
- Attachment
- Autocomplete
- Avatar
- Badge
- Bar List
- Breadcrumb
- Bubble
- Button
- Button Group
- Calendar
- Card
- Carousel
- Chat Message
- Checkbox
- Checkbox Group
- Circular Progress
- Collapsible
- Combobox
- Command
- Context Menu
- Copy Button
- Currency Input
- Data Table
- Date Picker
- Dialog
- Drawer
- Dropdown Menu
- Empty
- Field
- Hover Card
- Input
- Input Group
- Input Message
- Input OTP
- Item
- Kbd
- Label
- Marker
- Menubar
- Message
- Message Scroller
- Meter
- Multi Combobox
- Native Select
- Navigation Menu
- Number Field
- Pagination
- Phone Input
- Popover
- Progress
- Progress List
- Prompt
- Radio Group
- Resizable
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner
- Spinner
- Stat
- Switch
- Table
- Tabs
- Textarea
- Thinking Indicator
- Thinking Steps
- Toggle
- Toggle Group
- Tooltip
- Typography
Loading...
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Bubble, BubbleContent, BubbleGroup, BubbleReactions } from "@/components/ui/bubble";
import { Marker, MarkerContent } from "@/components/ui/marker";
import {
Message,
MessageAvatar,
MessageContent,
MessageFooter,
} from "@/components/ui/message";
export function MessageDemo() {
return (
<div className="flex w-full max-w-sm flex-col gap-6 py-12">
<Message align="end">
<MessageAvatar>
<Avatar>
<AvatarImage alt="@me" src="https://github.com/shadcn.png" />
<AvatarFallback>ME</AvatarFallback>
</Avatar>
</MessageAvatar>
<MessageContent>
<Bubble>
<BubbleContent>Deploying to prod real quick.</BubbleContent>
</Bubble>
</MessageContent>
</Message>
<Message>
<MessageAvatar>
<Avatar>
<AvatarImage alt="@rabbit" src="https://github.com/evilrabbit.png" />
<AvatarFallback>R</AvatarFallback>
</Avatar>
</MessageAvatar>
<MessageContent>
<Bubble variant="muted">
<BubbleContent>It's 4:55 PM. On a Friday.</BubbleContent>
</Bubble>
</MessageContent>
</Message>
<Message align="end">
<MessageAvatar>
<Avatar>
<AvatarImage alt="@me" src="https://github.com/shadcn.png" />
<AvatarFallback>ME</AvatarFallback>
</Avatar>
</MessageAvatar>
<MessageContent>
<Bubble>
<BubbleContent>It's a one-line change.</BubbleContent>
</Bubble>
<MessageFooter>Delivered</MessageFooter>
</MessageContent>
</Message>
<Message>
<MessageAvatar>
<Avatar>
<AvatarImage alt="@rabbit" src="https://github.com/evilrabbit.png" />
<AvatarFallback>R</AvatarFallback>
</Avatar>
</MessageAvatar>
<MessageContent>
<BubbleGroup>
<Bubble variant="muted">
<BubbleContent>It's always a one-line change 😭.</BubbleContent>
</Bubble>
<Bubble variant="muted">
<BubbleContent>Alright, let me take a look.</BubbleContent>
<BubbleReactions aria-label="Reactions: thumbs up">
<span>👍</span>
</BubbleReactions>
</Bubble>
</BubbleGroup>
</MessageContent>
</Message>
<Marker render={<output />}>
<MarkerContent className="shimmer">
<span className="font-medium">Oliver</span> is typing...
</MarkerContent>
</Marker>
</div>
);
}Installation
npx shadcn@latest add "https://ui.blode.co/r/styles/default/message"
Usage
import {
Message,
MessageAvatar,
MessageContent,
MessageFooter,
MessageGroup,
MessageHeader,
} from "@/components/ui/message";<Message align="end">
<MessageAvatar>
<Avatar>
<AvatarImage src="https://github.com/shadcn.png" alt="@me" />
<AvatarFallback>ME</AvatarFallback>
</Avatar>
</MessageAvatar>
<MessageContent>
<Bubble>
<BubbleContent>Deploying to prod real quick.</BubbleContent>
</Bubble>
<MessageFooter>Delivered</MessageFooter>
</MessageContent>
</Message>Related
Message and Bubble are the lower-level primitives
for building a chat transcript. For a higher-level, animated transcript entry
that styles user and assistant turns out of the box, see
Chat Message.
Examples
Avatar
Set align to end to reverse the row for the current user, and pass an
Avatar inside MessageAvatar.
Loading...
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Bubble, BubbleContent, BubbleGroup } from "@/components/ui/bubble";
import { Message, MessageAvatar, MessageContent } from "@/components/ui/message";
export function MessageAvatarDemo() {
return (
<div className="flex w-full max-w-sm flex-col gap-6 py-12">
<Message>
<MessageAvatar>
<Avatar>
<AvatarImage alt="@avatar" src="https://github.com/evilrabbit.png" />
<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="@avatar" src="https://github.com/shadcn.png" />
<AvatarFallback>R</AvatarFallback>
</Avatar>
</MessageAvatar>
<MessageContent>
<Bubble>
<BubbleContent>Can you share the exact error?</BubbleContent>
</Bubble>
</MessageContent>
</Message>
<Message>
<MessageAvatar>
<Avatar>
<AvatarImage alt="@avatar" src="https://github.com/evilrabbit.png" />
<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
Wrap consecutive messages from the same sender in MessageGroup to tighten the
spacing between them.
Loading...
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Bubble, BubbleContent } from "@/components/ui/bubble";
import {
Message,
MessageAvatar,
MessageContent,
MessageGroup,
} from "@/components/ui/message";
export function MessageGroupDemo() {
return (
<div className="flex w-full max-w-sm flex-col gap-6 py-12">
<MessageGroup>
<Message>
<MessageAvatar />
<MessageContent>
<Bubble variant="muted">
<BubbleContent>I checked the registry addresses.</BubbleContent>
</Bubble>
</MessageContent>
</Message>
<Message>
<MessageAvatar>
<Avatar>
<AvatarImage alt="@avatar" src="https://github.com/evilrabbit.png" />
<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>
);
}Header and footer
Use MessageHeader for a sender name and MessageFooter for delivery status or
timestamps.
Loading...
import { Bubble, BubbleContent } from "@/components/ui/bubble";
import {
Message,
MessageContent,
MessageFooter,
MessageHeader,
} from "@/components/ui/message";
export function MessageHeaderFooterDemo() {
return (
<div className="flex w-full max-w-sm flex-col gap-8 py-12">
<Message>
<MessageContent>
<MessageHeader>Olivia</MessageHeader>
<Bubble variant="muted">
<BubbleContent>I already checked the logs.</BubbleContent>
</Bubble>
</MessageContent>
</Message>
<Message align="end">
<MessageContent>
<Bubble>
<BubbleContent>
Send the report to the team. Ping @shadcn if you need help.
</BubbleContent>
</Bubble>
<MessageFooter>
<div>
Read <span className="font-normal">Yesterday</span>
</div>
</MessageFooter>
</MessageContent>
</Message>
</div>
);
}Actions
Place Button actions in the MessageFooter to copy, react to, or retry a
message.
Loading...
import { CopyIcon, RefreshCcwIcon, ThumbsDownIcon, ThumbsUpIcon } from "blode-icons-react";
import { Bubble, BubbleContent } from "@/components/ui/bubble";
import { Button } from "@/components/ui/button";
import { Message, MessageContent, MessageFooter } from "@/components/ui/message";
export function MessageActionsDemo() {
return (
<div className="flex w-full max-w-sm flex-col gap-8 py-12">
<Message>
<MessageContent>
<Bubble variant="muted">
<BubbleContent>The install failure is coming from the workspace package.</BubbleContent>
</Bubble>
<MessageFooter>
<Button aria-label="Copy" size="icon-sm" title="Copy" variant="ghost">
<CopyIcon />
</Button>
<Button aria-label="Like" size="icon-sm" title="Like" variant="ghost">
<ThumbsUpIcon />
</Button>
<Button aria-label="Dislike" size="icon-sm" title="Dislike" variant="ghost">
<ThumbsDownIcon />
</Button>
</MessageFooter>
</MessageContent>
</Message>
<Message align="end">
<MessageContent>
<Bubble>
<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>
);
}Attachment
Render an Attachment alongside the Bubble inside MessageContent to share
images and files.
Loading...
"use client";
import { DownloadIcon, FileTextIcon } from "blode-icons-react";
import Image from "next/image";
import {
Attachment,
AttachmentAction,
AttachmentActions,
AttachmentContent,
AttachmentDescription,
AttachmentMedia,
AttachmentTitle,
} from "@/components/ui/attachment";
import { Bubble, BubbleContent } from "@/components/ui/bubble";
import { Message, MessageContent } from "@/components/ui/message";
export function MessageAttachmentDemo() {
return (
<div className="flex w-full max-w-sm flex-col gap-8 py-12">
<Message align="end">
<MessageContent>
<Attachment orientation="vertical">
<AttachmentMedia variant="image">
<Image
alt="Workspace"
height={400}
src="https://images.unsplash.com/photo-1497366754035-f200968a6e72?w=900&auto=format&fit=crop&q=80"
width={400}
/>
</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>
);
}