Chat Message
blode-ui/chat-messageFreeComponent
A chat transcript entry for user and assistant messages, with attachments and a hover meta row.
Install it
npx shadcn@latest add https://raw.githubusercontent.com/mblode/blode-ui/main/public/r/chat-message.jsonSource
1"use client";23import { motion } from "motion/react";4import type { HTMLMotionProps } from "motion/react";5import type * as React from "react";67import { cn } from "@/lib/utils";8import { FileThumbnail } from "@/components/ui/file-thumbnail";910interface ChatMessageProps extends Omit<HTMLMotionProps<"div">, "children"> {11 /** Who sent the message. Drives alignment and styling: `user` →12 * right-aligned tonal bubble, `assistant` → left-aligned plain text. */13 from: "user" | "assistant";14 /** Optional attachments rendered as square thumbnails above the bubble. */15 files?: File[];16 /** Side length of each attachment thumbnail in pixels. Defaults to 64. */17 thumbnailSize?: number;18 /** Timestamp shown in the hover-revealed meta row (user messages only). */19 time?: React.ReactNode;20 /** Icon-only action buttons (copy, edit, regenerate) in the meta row. */21 actions?: React.ReactNode;22 /** Message body. Omit for an attachment-only message. */23 children?: React.ReactNode;24}2526// ─── ChatMessage ──────────────────────────────────────────────────────────27// A single transcript entry with baked-in entrance + layout motion. Pairs with28// InputMessage's onSend: render one per sent/received message. `layout="position"`29// lets earlier messages slide up smoothly when a new one is appended.30const ChatMessage = ({31 from,32 files,33 thumbnailSize = 64,34 time,35 actions,36 children,37 className,38 ref,39 ...props40}: ChatMessageProps) => {41 const isUser = from === "user";42 // Timestamps are a user-message affordance; assistant replies show actions only.43 const showTime = isUser && time !== undefined && time !== null;4445 return (46 <motion.div47 animate={{ opacity: 1, scale: 1, y: 0 }}48 className={cn(49 "group flex max-w-[80%] flex-col gap-1.5",50 isUser ? "items-end self-end" : "items-start self-start",51 className,52 )}53 data-slot="chat-message"54 initial={{ opacity: 0, scale: 0.96, y: 8 }}55 layout="position"56 ref={ref}57 style={{ transformOrigin: isUser ? "bottom right" : "bottom left" }}58 transition={{ bounce: 0.15, duration: 0.16, type: "spring" }}59 {...props}60 >61 {files && files.length > 0 && (62 <div className={cn("flex flex-wrap gap-1.5", isUser ? "justify-end" : "justify-start")}>63 {files.map((file, i) => (64 <FileThumbnail65// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from blode/ui
All 85 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | blode/ui | Components | Free | 2 deps | |
| Alertalert | blode/ui | Components | Free | no deps | |
| Alert Dialogalert-dialog | blode/ui | Components | Free | 1 dep | |
| Ask User Questionsask-user-questions | blode/ui | Components | Free | 1 dep | |
| Aspect Ratioaspect-ratio | blode/ui | Components | Free | 1 dep | |
| Attachmentattachment | blode/ui | Components | Free | 1 dep | |
| Autocompleteautocomplete | blode/ui | Components | Free | 1 dep | |
| Avataravatar | blode/ui | Components | Free | 1 dep |
