|Design System

AI Component

Chat Bubble

Message container for conversational AI interfaces with user/assistant roles, timestamps, and streaming state.

Preview

Analyze the Q4 revenue data.

2:33 PM

AI

Here is the analysis you requested. I found three key insights from the data.

2:34 PM

AI

Source

Full component implementation using the design system tokens.

tsx
"use client";

export function DSChatBubble({
  role = "assistant",
  avatar,
  timestamp,
  streaming = false,
  children,
}: {
  role?: "user" | "assistant";
  avatar?: string;
  timestamp?: string;
  streaming?: boolean;
  children?: React.ReactNode;
}) {
  if (role === "user") {
    return (
      <div className="flex justify-end gap-3">
        <div className="max-w-xs">
          <div className="bg-contrast text-background rounded-xl rounded-tr-sm px-4 py-3">
            <p className="text-sm leading-relaxed">{children}</p>
          </div>
          {timestamp && (
            <p className="text-xs text-tertiary mt-1 text-right">{timestamp}</p>
          )}
        </div>
      </div>
    );
  }

  return (
    <div className="flex gap-3">
      <div className="w-8 h-8 rounded-full bg-accent/20 border border-accent/30 shrink-0 flex items-center justify-center text-xs font-medium text-accent">
        {avatar || "AI"}
      </div>
      <div className="max-w-xs">
        <div className="bg-surface rounded-xl rounded-tl-sm px-4 py-3">
          {streaming ? (
            <div className="flex items-center gap-1 py-1">
              <span className="w-1.5 h-1.5 rounded-full bg-secondary animate-bounce" style={{ animationDelay: "0ms" }} />
              <span className="w-1.5 h-1.5 rounded-full bg-secondary animate-bounce" style={{ animationDelay: "150ms" }} />
              <span className="w-1.5 h-1.5 rounded-full bg-secondary animate-bounce" style={{ animationDelay: "300ms" }} />
            </div>
          ) : (
            <p className="text-sm text-foreground leading-relaxed">{children}</p>
          )}
        </div>
        {timestamp && (
          <p className="text-xs text-tertiary mt-1">{timestamp}</p>
        )}
      </div>
    </div>
  );
}

Props

All available props with types and defaults.

PropTypeDescription
childrenReactNodeMessage content
role'user' | 'assistant'Message sender role — determines alignment and styling
avatarstringAvatar text or initials for assistant messages
timestampstringTimestamp displayed below the message
streamingbooleanShows animated dots indicating generation in progress

Variants

Assistant message

Left-aligned with avatar. The default for AI-generated responses.

AI

Here is the analysis you requested.

2:34 PM

tsx
<DSChatBubble role="assistant" timestamp="2:34 PM">
  Here is the analysis you requested.
</DSChatBubble>

User message

Right-aligned with contrast background. Visually distinct from AI responses.

Analyze the Q4 revenue data.

2:33 PM

tsx
<DSChatBubble role="user" timestamp="2:33 PM">
  Analyze the Q4 revenue data.
</DSChatBubble>

Streaming

Animated loading dots while the AI generates a response.

AI
tsx
<DSChatBubble role="assistant" streaming />

Prompt Guide

Prompt Guide — Chat Bubble

Use for

  • Conversational AI chat interfaces
  • Multi-turn dialogue displays
  • Customer support chat widgets
  • AI assistant embedded panels

Don't use for

  • Comment threads — comments have different interaction patterns
  • Notification feeds — use a list with badges instead
  • Single-response displays — if there is no conversation, just render the text

AI Context

The core primitive of conversational AI. User messages are right-aligned with contrast backgrounds so users can instantly distinguish their input from AI output. The streaming state is critical — show it immediately when a generation starts, before any tokens arrive. Avatar defaults to 'AI' but accepts model-specific labels. Timestamps use Caption (12px) + tertiary color — present but never competing with message content.