Message Bubble
beui/message-bubbleFreeComponent
A focused conversational surface with visual tones, independent alignment, grouped messages, expandable content, and interactive link or button support.
Install it
npx shadcn@latest add https://beui.dev/r/message-bubble.jsonSource
1"use client";2// beui.dev/components/agents/message-bubble34import { ChevronDown } from "lucide-react";5import {6 type HTMLMotionProps,7 motion,8 useReducedMotion,9} from "motion/react";10import {11 cloneElement,12 type ComponentPropsWithRef,13 createContext,14 type ReactElement,15 type ReactNode,16 type Ref,17 useCallback,18 useContext,19 useId,20 useState,21} from "react";22import {23 EASE_OUT,24 SPRING_LAYOUT,25 SPRING_SWAP,26} from "@/lib/ease";27import { cn } from "@/lib/utils";28import { MessageSideContext } from "@/components/agents/message-context";2930export type MessageBubbleVariant =31 | "solid"32 | "soft"33 | "tint"34 | "outline"35 | "ghost"36 | "danger";37export type MessageBubbleAlign = "start" | "end";3839interface MessageBubbleContextValue {40 align?: MessageBubbleAlign;41 animateIn: boolean;42 variant: MessageBubbleVariant;43}4445const MessageBubbleContext = createContext<MessageBubbleContextValue>({46 animateIn: true,47 variant: "soft",48});49const MessageBubbleLayoutContext = createContext<() => void>(() => {});5051export interface MessageBubbleProps52 extends Omit<HTMLMotionProps<"div">, "children"> {53 variant?: MessageBubbleVariant;54 /** Defaults to the surrounding Message alignment when omitted. */55 align?: MessageBubbleAlign;56 /** Plays the bubble entrance once when this component mounts. */57 animateIn?: boolean;58 children?: ReactNode;59}6061export interface MessageBubbleContentProps62 extends ComponentPropsWithRef<"div"> {63 /** Replaces the content element while preserving bubble styling. */64 render?: ReactElement;65}6667export interface MessageBubbleGroupProps extends ComponentPropsWithRef<"div"> {68 spacing?: "compact" | "default";69}7071export interface MessageBubbleCollapsibleProps72 extends ComponentPropsWithRef<"div"> {73 open?: boolean;74 defaultOpen?: boolean;75 onOpenChange?: (open: boolean) => void;76 collapsedLines?: 2 | 3 | 4 | 5 | 6;77 moreLabel?: ReactNode;78 lessLabel?: ReactNode;79 contentClassName?: string;80 triggerClassName?: string;81 children?: ReactNode;82}8384function mergeRefs<T>(...refs: Array<Ref<T> | undefined>) {85 return (node: T | null) => {86 for (const ref of refs) {87 if (typeof ref === "function") ref(node);88 else if (ref) ref.current = node;89 }90 };91}9293const BUBBLE_CONTENT_REVEAL = {94 duration: 0.12,95 ease: EASE_OUT,96 delay: 0.04,97} as const;9899// Sent bubbles should pop into place quickly with one restrained overshoot.100const BUBBLE_POP = {101 type: "spring",102 stiffness: 520,103 damping: 27,104// … truncated
What it pulls in
npm packages
Files it writes
More from beui
All 104 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Action Swap Bluraction-swap-blur | beui | Components | Free | 3 deps · 4 files | |
| Action Swap Cascadeaction-swap-cascade | beui | Components | Free | 3 deps · 4 files | |
| Action Swap Rollaction-swap-roll | beui | Components | Free | 3 deps · 4 files | |
| Agent Activityagent-activity | beui | Components | Free | 4 deps · 9 files | |
| Agent Loading States Agent Progressagent-progress | beui | Components | Free | 3 deps · 3 files | |
| AI Sidebarai-sidebar | beui | Components | Free | 4 deps · 5 files | |
| Animated Badgeanimated-badge | beui | Components | Free | 4 deps · 3 files | |
| Number Animation Animated Numberanimated-number | beui | Components | Free | 3 deps · 3 files |
