MynaUI
No results found.
Theme
Toggle Theme (Dark)
Documentation
Getting Started
Design System
Changelog
Icons
Elements
Accordion
Alert
Alert Dialog
Avatar
Avatar Groups
Badge
Breadcrumb
Button
Button Groups
Calendar
Combobox
Command
Context Menu
Data Table
Dialog
Drawer
Dropdown Menu
Menubar
Pagination
Popover
Progress
Rating
Sheet
Skeleton
Spinner
Table
Tabs
Toast
Toggle and Toggle Group
Tooltip
Forms
Checkbox
Date Picker
Input
Input OTP
Radio
Select
Slider
Switch
Textarea
Marketing
404
Banners
Blog List
Blog Post
Call to Action
Cookies
FAQ
Features
Footer
Gallery
Header
Hero
Newsletters
Statistics
Testimonial Logos
Application
App Headers
App Sheets
Application Dialogs
Card Headers
Cards
Chat
Code Block
Containers
Dividers
Empty States
Forgot Password
Login
Notifications
Registration
Section Headers
Documentation
  • Getting Started
  • Copybook
  • Design System
  • Icons
  • Changelog
  • Figma
  • Request Components
  • Request Icons
Elements
  • Accordion
  • Alert
  • Alert Dialog
  • Avatar
  • Avatar Groups
  • Badge
  • Breadcrumb
  • Button
  • Button Groups
  • Calendar
  • Combobox
  • Command
  • Context Menu
  • Data Table
  • Dialog
  • Drawer
  • Dropdown Menu
  • Menubar
  • Pagination
  • Popover
  • Progress
  • Rating
  • Sheet
  • Skeleton
  • Spinner
  • Table
  • Tabs
  • Toast
  • Toggle and Toggle Group
  • Tooltip
Forms
  • Checkbox
  • Date Picker
  • Input
  • Input OTP
  • Radio
  • Select
  • Slider
  • Switch
  • Textarea
Marketing
  • 404
  • Banners
  • Blog List
  • Blog Post
  • Call to Action
  • Cookies
  • FAQ
  • Features
  • Footer
  • Gallery
  • Header
  • Hero
  • Newsletters
  • Statistics
  • Testimonial Logos
Application
  • App Headers
  • App Sheets
  • Application Dialogs
  • Card Headers
  • Cards
  • Chat
  • Code Block
  • Containers
  • Dividers
  • Empty States
  • Forgot Password
  • Login
  • Notifications
  • Registration
  • Section Headers
Newsletter

Get the latest news and updates from MynaUI

Subscribe for Updates

Chat

Message bubbles and conversation areas for direct and group messaging.

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

export default function ChatBubbles() {
  return (
    <div className="mx-auto flex w-full max-w-lg flex-col gap-5">
      <Message>
        <MessageAvatar>
          <Avatar className="size-8">
            <AvatarImage src="/avatars/avatar-04.webp" alt="Maya Chen" />
            <AvatarFallback>MC</AvatarFallback>
          </Avatar>
        </MessageAvatar>
        <MessageContent>
          <MessageHeader>Maya · 10:24 AM</MessageHeader>
          <BubbleGroup>
            <Bubble variant="secondary">
              <BubbleContent>Hey! Are we still on for the design review?</BubbleContent>
            </Bubble>
            <Bubble variant="secondary">
              <BubbleContent>I added the latest notes to the prototype.</BubbleContent>
            </Bubble>
          </BubbleGroup>
        </MessageContent>
      </Message>

      <Message align="end">
        <MessageContent>
          <Bubble variant="default">
            <BubbleContent>Yes, I’ll join in five. Looking forward to it.</BubbleContent>
          </Bubble>
          <MessageFooter>Seen 10:26 AM</MessageFooter>
        </MessageContent>
      </Message>
    </div>
  )
}
"use client"

import type { SyntheticEvent } from "react"
import { ArrowUp, Paperclip, Video } from "lucide-react"

import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Bubble, BubbleContent } from "@/components/ui/bubble"
import { Button } from "@/components/ui/button"
import {
  InputGroup,
  InputGroupAddon,
  InputGroupButton,
  InputGroupTextarea,
} from "@/components/ui/input-group"
import { Marker, MarkerContent } from "@/components/ui/marker"
import { Message, MessageContent, MessageFooter } from "@/components/ui/message"
import {
  MessageScroller,
  MessageScrollerButton,
  MessageScrollerContent,
  MessageScrollerItem,
  MessageScrollerProvider,
  MessageScrollerViewport,
} from "@/components/ui/message-scroller"

const messages = [
  { id: "1", side: "start", text: "Could you share the updated launch date?" },
  { id: "2", side: "end", text: "We’re targeting Thursday, after the final QA pass." },
  { id: "3", side: "start", text: "Perfect. I’ll update the release notes today." },
] as const

export default function DirectMessage() {
  function handleSubmit(event: SyntheticEvent<HTMLFormElement>) {
    event.preventDefault()
  }

  return (
    <section className="mx-auto flex h-[32rem] w-full max-w-md flex-col overflow-hidden rounded-xl border bg-background shadow-sm">
      <header className="flex h-14 shrink-0 items-center gap-3 border-b px-4">
        <Avatar className="size-8">
          <AvatarImage src="/avatars/avatar-02.webp" alt="Noah Williams" />
          <AvatarFallback>NW</AvatarFallback>
        </Avatar>
        <div className="min-w-0 flex-1">
          <p className="truncate text-sm font-medium">Noah Williams</p>
          <p className="text-xs text-muted-foreground">Active now</p>
        </div>
        <Button variant="ghost" size="icon-sm" aria-label="Start a video call">
          <Video />
        </Button>
      </header>

      <MessageScrollerProvider defaultScrollPosition="end">
        <MessageScroller className="flex-1">
          <MessageScrollerViewport aria-label="Conversation with Noah Williams">
            <MessageScrollerContent className="justify-end gap-4 p-4">
              <Marker variant="separator">
                <MarkerContent>Today</MarkerContent>
              </Marker>
              {messages.map((message, index) => (
                <MessageScrollerItem
                  key={message.id}
                  messageId={message.id}
                  scrollAnchor={index === messages.length - 1}
                >
                  <Message align={message.side}>
                    <MessageContent>
                      <Bubble variant={message.side === "end" ? "default" : "secondary"}>
                        <BubbleContent>{message.text}</BubbleContent>
                      </Bubble>
                      {index === messages.length - 1 && (
                        <MessageFooter>Delivered</MessageFooter>
                      )}
                    </MessageContent>
                  </Message>
                </MessageScrollerItem>
              ))}
            </MessageScrollerContent>
          </MessageScrollerViewport>
          <MessageScrollerButton />
        </MessageScroller>
      </MessageScrollerProvider>

      <form className="border-t p-3" onSubmit={handleSubmit}>
        <InputGroup className="h-auto rounded-xl">
          <InputGroupTextarea
            aria-label="Message Noah"
            placeholder="Write a message…"
            className="min-h-10 max-h-28"
          />
          <InputGroupAddon align="block-end" className="justify-between">
            <InputGroupButton size="icon-xs" aria-label="Attach a file">
              <Paperclip />
            </InputGroupButton>
            <InputGroupButton
              type="submit"
              variant="default"
              size="icon-xs"
              className="rounded-full"
              aria-label="Send message"
            >
              <ArrowUp />
            </InputGroupButton>
          </InputGroupAddon>
        </InputGroup>
      </form>
    </section>
  )
}
import { CheckCheck, FileText, MoreHorizontal } from "lucide-react"

import {
  Attachment,
  AttachmentAction,
  AttachmentActions,
  AttachmentContent,
  AttachmentDescription,
  AttachmentGroup,
  AttachmentMedia,
  AttachmentTitle,
} from "@/components/ui/attachment"
import { Bubble, BubbleContent } from "@/components/ui/bubble"
import { Marker, MarkerContent, MarkerIcon } from "@/components/ui/marker"
import { Message, MessageContent, MessageFooter, MessageHeader } from "@/components/ui/message"

export default function ProjectThread() {
  return (
    <div className="mx-auto flex w-full max-w-xl flex-col gap-5 rounded-xl border bg-background p-4 sm:p-6">
      <Marker variant="separator">
        <MarkerContent>2 unread messages</MarkerContent>
      </Marker>

      <Message>
        <MessageContent>
          <MessageHeader>Jamie · 2:14 PM</MessageHeader>
          <Bubble variant="secondary">
            <BubbleContent>
              I’ve attached the final copy deck. The revised sections are highlighted.
            </BubbleContent>
          </Bubble>
          <AttachmentGroup>
            <Attachment size="sm">
              <AttachmentMedia>
                <FileText />
              </AttachmentMedia>
              <AttachmentContent>
                <AttachmentTitle>Launch copy.pdf</AttachmentTitle>
                <AttachmentDescription>2.4 MB · PDF</AttachmentDescription>
              </AttachmentContent>
              <AttachmentActions>
                <AttachmentAction aria-label="More attachment actions">
                  <MoreHorizontal />
                </AttachmentAction>
              </AttachmentActions>
            </Attachment>
          </AttachmentGroup>
        </MessageContent>
      </Message>

      <Message align="end">
        <MessageContent>
          <Bubble variant="tinted">
            <BubbleContent>Got it. I’ll review this before our check-in.</BubbleContent>
          </Bubble>
          <MessageFooter className="gap-1">
            <CheckCheck aria-hidden="true" /> Seen by Jamie
          </MessageFooter>
        </MessageContent>
      </Message>

      <Marker variant="border">
        <MarkerIcon>
          <CheckCheck />
        </MarkerIcon>
        <MarkerContent>All caught up</MarkerContent>
      </Marker>
    </div>
  )
}

Not affiliated with Figma, TailwindCSS or shadcn/ui.