Chat Component

A customizable chat window component built with Shadcn UI and React.

AS
Ann SmithAKAFront-end developer
Oh, and could you also share those user feedback notes? I want to make sure we're really nailing what they need before we ship this.
Jo
John Doe
Just tested the new checkout flow - it's so smooth! The loading states you added make such a difference. Customers are gonna love this! 🚀
Jo
John Doe
Sweet! I'll check it out on mobile too and let you know. Thanks for keeping accessibility in mind - that's real value right there!
But first, could you give the responsive design a quick look? I want to make sure it feels great on all devices before we show it to users.
An
Ann Smith
Hey! Just wrapped up the dashboard redesign. Focused on making the key metrics super easy to find - think our users will really appreciate it!
Also, how's the performance optimization going? Any wins on those load times we discussed?
Jo
John Doe
Hey! How's it going? Did you get a chance to look at those user journey mockups? Want to make sure we're solving the right problems for them.
I'll ping you here once it's ready for a demo!
Perfect! Time to build something awesome ✨
An
Ann Smith
Awesome, thanks! That totally makes sense now. I love how we're thinking about the end user experience here. Can't wait to see their reaction when this goes live!
So basically - keep the interactions snappy, add subtle animations for feedback, and make sure error states are super clear. When users feel confident using the interface, they stick around. That's the value we're delivering! 😊
Here's what I'm thinking:
Absolutely! Let me pull up my notes from the customer interviews
Jo
John Doe
Hey! Doing great, thanks for asking!
Could you share your thoughts on the UX flow? Want to make sure we're creating real value for our users.
An
Ann Smith
Hey there! How's your day going?

Installation

Prerequisites

The chat component is compatible with any environment that supports React and has shadcn/ui configured.

This guide assumes you are already familiar with both of these technologies. If you are not, you can review their documentation here.

This will install all the chat components and their dependencies into your project.

pnpm dlx shadcn@latest add https://shadcn-chat.vercel.app/r/chat.json

Usage Example

Chat

The root container component that establishes the chat layout structure with container queries and flex column layout for header, messages, and toolbar sections.

Responsiveness

The Chat component uses container queries (ex. @2xl/chat:) to adapt its layout based on the available width, ensuring an optimal user experience across different device sizes.

Make sure that the Chat component is given a defined height or max-height (ex. via CSS or parent container) to enable proper scrolling behavior for the messages section.

1<Chat className="h-screen">
2  <ChatHeader>
3    {/* Header Content */}
4  </ChatHeader>
5
6  <ChatMessages>
7    {/* Messages Content */}
8  </ChatMessages>
9
10  <ChatToolbar>
11    {/* Toolbar Content */}
12  </ChatToolbar>
13</Chat>;   
14    

Chat Header

A sticky header component with flexible layout. Use ChatHeaderMain for the primary content area (takes remaining space) and ChatHeaderAddon for grouping items on either side. Includes ChatHeaderAvatar for profile images and ChatHeaderButton for action buttons.

AS
Ann SmithAKAFront-end developer
1<ChatHeader className="border-b">
2  <ChatHeaderAddon>
3    <ChatHeaderAvatar
4      src="https://cdn.jsdelivr.net/gh/alohe/avatars/png/upstream_20.png"
5      alt="@annsmith"
6      fallback="AS"
7    />
8  </ChatHeaderAddon>
9
10  <ChatHeaderMain>
11    <span className="font-medium">Ann Smith</span>
12    <span className="text-sm font-semibold">AKA</span>
13    <span className="flex-1 grid">
14      <span className="text-sm font-medium truncate">
15        Front-end developer
16      </span>
17    </span>
18  </ChatHeaderMain>
19
20  <ChatHeaderAddon>
21    <InputGroup className="@2xl/chat:flex hidden">
22      <InputGroupInput placeholder="Search..." />
23      <InputGroupAddon>
24        <SearchIcon />
25      </InputGroupAddon>
26    </InputGroup>
27    <ChatHeaderButton className="@2xl/chat:inline-flex hidden">
28      <PhoneIcon />
29    </ChatHeaderButton>
30    <ChatHeaderButton className="@2xl/chat:inline-flex hidden">
31      <VideoIcon />
32    </ChatHeaderButton>
33    <ChatHeaderButton>
34      <MoreHorizontalIcon />
35    </ChatHeaderButton>
36  </ChatHeaderAddon>
37  </ChatHeader>
38</ChatHeader>
39    

Chat Messages

A scrollable flex container with reverse column direction that displays chat messages from bottom to top, automatically handling overflow.

1<ChatMessages>
2  {MESSAGES.map((msg, i, msgs) => {
3    // If date changed, show date item
4    if (
5      new Date(msg.timestamp).toDateString() !==
6      new Date(msgs[i + 1]?.timestamp).toDateString()
7    ) {
8      return (
9        <Fragment key={msg.id}>
10          <PrimaryMessage
11            avatarSrc={msg.sender.avatarUrl}
12            avatarAlt={msg.sender.username}
13            avatarFallback={msg.sender.name.slice(0, 2)}
14            senderName={msg.sender.name}
15            content={msg.content}
16            timestamp={msg.timestamp}
17          />
18          <DateItem timestamp={msg.timestamp} className="my-4" />
19        </Fragment>
20      );
21    }
22
23    // If next item is same user, show additional
24    if (msg.sender.id === msgs[i + 1]?.sender.id) {
25      return (
26        <AdditionalMessage
27          key={msg.id}
28          content={msg.content}
29          timestamp={msg.timestamp}
30        />
31      );
32    }
33    // Else, show primary
34    else {
35      return (
36        <PrimaryMessage
37          className="mt-4"
38          key={msg.id}
39          avatarSrc={msg.sender.avatarUrl}
40          avatarAlt={msg.sender.username}
41          avatarFallback={msg.sender.name.slice(0, 2)}
42          senderName={msg.sender.name}
43          content={msg.content}
44          timestamp={msg.timestamp}
45        />
46      );
47    }
48  })}
49</ChatMessages>
50    

Chat Event

A flexible message row component for displaying any message or event in the chat. Use ChatEventAddon for side content like avatars or timestamps, and ChatEventBody for the main content area. Inside the body, use ChatEventTitle for sender name and metadata, and ChatEventContent for the message text. Use ChatEventAvatar for profile images and ChatEventTime for localized timestamp formatting with preset formats.

Primary Message

Jo
John Doe
Just tested the new checkout flow - it's so smooth! The loading states you added make such a difference. Customers are gonna love this! 🚀
1export function PrimaryMessage({
2  avatarSrc,
3  avatarAlt,
4  avatarFallback,
5  senderName,
6  content,
7  timestamp,
8  className,
9}: {
10  avatarSrc?: string;
11  avatarAlt?: string;
12  avatarFallback?: string;
13  senderName: string;
14  content: ReactNode;
15  timestamp: number;
16  className?: string;
17}) {
18  return (
19    <ChatEvent className={cn("hover:bg-accent", className)}>
20      <ChatEventAddon>
21        <ChatEventAvatar
22          src={avatarSrc}
23          alt={avatarAlt}
24          fallback={avatarFallback}
25        />
26      </ChatEventAddon>
27      <ChatEventBody>
28        <ChatEventTitle>
29          <span className="font-medium">{senderName}</span>
30          <ChatEventTime timestamp={timestamp} />
31        </ChatEventTitle>
32        <ChatEventContent>{content}</ChatEventContent>
33      </ChatEventBody>
34    </ChatEvent>
35  );
36}
37

Additional Message

Oh, and could you also share those user feedback notes? I want to make sure we're really nailing what they need before we ship this.
1export function AdditionalMessage({
2  content,
3  timestamp,
4}: {
5  content: ReactNode;
6  timestamp: number;
7}) {
8  return (
9    <ChatEvent className="hover:bg-accent group">
10      <ChatEventAddon>
11        <ChatEventTime
12          timestamp={timestamp}
13          format="time"
14          className="text-right text-[8px] @md/chat:text-[10px] group-hover:visible invisible"
15        />
16      </ChatEventAddon>
17      <ChatEventBody>
18        <ChatEventContent>{content}</ChatEventContent>
19      </ChatEventBody>
20    </ChatEvent>
21  );
22}
23

Date Item

1export function DateItem({
2  timestamp,
3  className,
4}: {
5  timestamp: number;
6  className?: string;
7}) {
8  return (
9    <ChatEvent className={cn("items-center gap-1", className)}>
10      <Separator className="flex-1" />
11      <ChatEventTime
12        timestamp={timestamp}
13        format="longDate"
14        className="font-semibold min-w-max"
15      />
16      <Separator className="flex-1" />
17    </ChatEvent>
18  );
19}
20

Chat Toolbar

A sticky bottom input area for message composition. Use ChatToolbar as the container, ChatToolbarTextarea for the input field with built-in submit handling (Enter to submit, Shift+Enter for new line), and ChatToolbarAddon to position action buttons using the align prop ("inline-start", "inline-end", "block-start", "block-end"). Use ChatToolbarButton for consistent icon button styling.

1<ChatToolbar>
2  <ChatToolbarAddon align="inline-start">
3    <ChatToolbarButton>
4      <PlusIcon />
5    </ChatToolbarButton>
6  </ChatToolbarAddon>
7
8  <ChatToolbarTextarea
9    value={message}
10    onChange={(e) => setMessage(e.target.value)}
11    onSubmit={() => handleSendMessage()}
12  />
13  
14  <ChatToolbarAddon align="inline-end">
15    <ChatToolbarButton>
16      <GiftIcon />
17    </ChatToolbarButton>
18    <ChatToolbarButton>
19      <CalendarDaysIcon />
20    </ChatToolbarButton>
21    <ChatToolbarButton>
22      <SquareChevronRightIcon />
23    </ChatToolbarButton>
24  </ChatToolbarAddon>
25</ChatToolbar>
26

Enjoying the Component?

If you found this useful, consider giving it a star on GitHub. Got ideas or feedback? Open an issue — every bit helps!