Chat Component

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

ASAnn Smith
AKAFront-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
Feb 17, 2009, 1:41 PM
Just tested the new checkout flow - it's so smooth! The loading states you added make such a difference. Customers are gonna love this! 🚀
February 17, 2009
Jo
John Doe
Feb 15, 2009, 6:08 AM
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
Feb 15, 2009, 6:07 AM
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
Feb 15, 2009, 6:05 AM
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.
February 15, 2009
I'll ping you here once it's ready for a demo!
Perfect! Time to build something awesome ✨
An
Ann Smith
Feb 13, 2009, 11:31 PM
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
Feb 13, 2009, 11:31 PM
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
Feb 13, 2009, 11:31 PM
Hey there! How's your day going?
February 13, 2009

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, please review their documentation first.

Quick Start

  1. Install shadcn/ui: If you haven't already, initialize shadcn/ui in your project by following the official installation guide.
  2. Install Dependencies: Ensure you have the necessary primitives installed.
    pnpm dlx shadcn@latest add textarea
  3. Copy the Chat Component: Copy the chat component files from the repository into your project's components directory (e.g., @/components/chat).
  4. Import and Use: Import the component into your page and use it as needed.

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.

1<Chat>
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 three sections (Start, Main, End) for displaying chat participant info, status, search, and action buttons.

ASAnn Smith
AKAFront-end developer
1<ChatHeader className="border-b">
2  <ChatHeaderStart>
3    <Avatar className="rounded-full size-6">
4      <AvatarImage src="https://github.com/evilrabbit.png" alt="@evilrabbit" />
5      <AvatarFallback>ER</AvatarFallback>
6    </Avatar>
7    <span className="font-medium">Evil Rabbit</span>
8  </ChatHeaderStart>
9  <ChatHeaderMain>
10    <span className="text-sm font-semibold">AKA</span>
11    <span className="text-sm font-medium">Chocolate Bunny</span>
12  </ChatHeaderMain>
13  <ChatHeaderEnd>
14    <InputGroup className="@2xl/chat:flex hidden">
15      <InputGroupInput placeholder="Search..." />
16      <InputGroupAddon>
17        <SearchIcon />
18      </InputGroupAddon>
19    </InputGroup>
20    <Button variant="ghost" className="size-8 @2xl/chat:inline-flex hidden">
21      <PhoneIcon />
22    </Button>
23    <Button variant="ghost" className="size-8 @2xl/chat:inline-flex hidden">
24      <VideoIcon />
25    </Button>
26    <Button variant="ghost" className="size-8">
27      <MoreHorizontalIcon />
28    </Button>
29  </ChatHeaderEnd>
30</ChatHeader>
31    

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 with Addon (for avatar/timestamp) and Body sections, supporting any message or event in the chat.

Primary Message

Jo
John Doe
Feb 17, 2009, 1:41 PM
Just tested the new checkout flow - it's so smooth! The loading states you added make such a difference. Customers are gonna love this! 🚀
1import { ReactNode } from "react";
2import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
3import { cn } from "@/lib/utils";
4import {
5  ChatEvent,
6  ChatEventAddon,
7  ChatEventBody,
8  ChatEventContent,
9  ChatEventDescription,
10  ChatEventTitle,
11} from "@/components/ui/chat-event";
12
13export function PrimaryMessage({
14  avatarSrc,
15  avatarAlt,
16  avatarFallback,
17  senderName,
18  content,
19  timestamp,
20  className,
21}: {
22  avatarSrc?: string;
23  avatarAlt?: string;
24  avatarFallback?: string;
25  senderName: string;
26  content: ReactNode;
27  timestamp: number;
28  className?: string;
29}) {
30  return (
31    <ChatEvent className={cn("hover:bg-accent", className)}>
32      <ChatEventAddon>
33        <Avatar className="rounded-full size-8 @md/chat:size-10 mx-auto">
34          <AvatarImage src={avatarSrc} alt={avatarAlt} />
35          <AvatarFallback>{avatarFallback}</AvatarFallback>
36        </Avatar>
37      </ChatEventAddon>
38      <ChatEventBody>
39        <div className="flex items-baseline gap-2">
40          <ChatEventTitle>{senderName}</ChatEventTitle>
41          <ChatEventDescription>
42            {new Intl.DateTimeFormat("en-US", {
43              dateStyle: "medium",
44              timeStyle: "short",
45            }).format(timestamp)}
46          </ChatEventDescription>
47        </div>
48        <ChatEventContent>{content}</ChatEventContent>
49      </ChatEventBody>
50    </ChatEvent>
51  );
52}
53  

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.
1import { ReactNode } from "react";
2import {
3  ChatEvent,
4  ChatEventAddon,
5  ChatEventBody,
6  ChatEventContent,
7  ChatEventDescription,
8} from "@/components/ui/chat-event";
9
10export function AdditionalMessage({
11  content,
12  timestamp,
13}: {
14  content: ReactNode;
15  timestamp: number;
16}) {
17  return (
18    <ChatEvent className="hover:bg-accent group">
19      <ChatEventAddon>
20        <ChatEventDescription className="text-right text-[8px] @md/chat:text-[10px] group-hover:visible invisible">
21          {new Intl.DateTimeFormat("en-US", {
22            timeStyle: "short",
23          }).format(timestamp)}
24        </ChatEventDescription>
25      </ChatEventAddon>
26      <ChatEventBody>
27        <ChatEventContent>{content}</ChatEventContent>
28      </ChatEventBody>
29    </ChatEvent>
30  );
31}
32

Date Item

February 17, 2009
1import { Separator } from "@/components/ui/separator";
2import { cn } from "@/lib/utils";
3import { ChatEvent } from "@/components/ui/chat-event";
4
5export function DateItem({
6  timestamp,
7  className,
8}: {
9  timestamp: number;
10  className?: string;
11}) {
12  return (
13    <ChatEvent className={cn("items-center gap-1", className)}>
14      <Separator className="flex-1" />
15      <span className="text-muted-foreground text-xs font-semibold min-w-max">
16        {new Intl.DateTimeFormat("en-US", {
17          dateStyle: "long",
18        }).format(timestamp)}
19      </span>
20      <Separator className="flex-1" />
21    </ChatEvent>
22  );
23}
24

Chat Toolbar

A sticky bottom input area with a three-column grid layout (AddonStart, Textarea, AddonEnd) for message composition with optional action buttons on both sides.

1<ChatToolbar>
2  <ChatToolbarAddonStart>
3    <Button variant="ghost" className="size-8 @md/chat:size-9">
4      <PlusIcon className="size-5 @md/chat:size-6 stroke-[1.7px]" />
5    </Button>
6  </ChatToolbarAddonStart>
7  <ChatToolbarTextarea />
8  <ChatToolbarAddonEnd>
9    <Button variant="ghost" className="size-8 @md/chat:size-9">
10      <GiftIcon className="size-4 @md/chat:size-5 stroke-[1.7px]" />
11    </Button>
12    <Button variant="ghost" className="size-8 @md/chat:size-9">
13      <CalendarDaysIcon className="size-4 @md/chat:size-5 stroke-[1.7px]" />
14    </Button>
15    <Button variant="ghost" className="size-8 @md/chat:size-9">
16      <SquareChevronRightIcon className="size-4 @md/chat:size-5 stroke-[1.7px]" />
17    </Button>
18  </ChatToolbarAddonEnd>
19</ChatToolbar>
20