ChatMessage

ChatMessage separates user and agent turns while keeping the transcript compact. Its body text uses the surrounding size scope, while its optional time and actions use lower typography.

I found three relevant results.
import { Button, ChatMessage } from "density-base-ui";
import { Copy, RefreshCw } from "lucide-react";

export default function ChatMessageExample() {
  return (
    <ChatMessage
      actions={
        <>
          <Button aria-label="Copy response" emphasis="ghost-primary" size="xs">
            <Copy aria-hidden="true" size={14} />
          </Button>
          <Button
            aria-label="Refresh response"
            emphasis="ghost-primary"
            size="xs"
          >
            <RefreshCw aria-hidden="true" size={14} />
          </Button>
        </>
      }
      author="agent"
      time="Just now"
    >
      I found three relevant results.
    </ChatMessage>
  );
}

Author

Use author to distinguish the human message from the agent message.

Agent messages align to the start.
User messages align to the end.
import { Button, ChatMessage, View } from "density-base-ui";
import { Copy, RefreshCw } from "lucide-react";

export default function ChatMessageAuthorExample() {
  return (
    <View gap="3xl" padding={false}>
      <ChatMessage
        actions={
          <>
            <Button
              aria-label="Copy response"
              emphasis="ghost-primary"
              size="xs"
            >
              <Copy aria-hidden="true" size={14} />
            </Button>
            <Button
              aria-label="Refresh response"
              emphasis="ghost-primary"
              size="xs"
            >
              <RefreshCw aria-hidden="true" size={14} />
            </Button>
          </>
        }
        author="agent"
        time="Just now"
      >
        Agent messages align to the start.
      </ChatMessage>
      <ChatMessage author="user">User messages align to the end.</ChatMessage>
    </View>
  );
}

Animate

Set animate on an agent message with string content to reveal comma-separated text parts in sequence when the message mounts. Change animationKey to replay an enabled animation. User messages and non-string content remain static.

I found three relevant results, each with current information.
import { Button, ChatMessage, View } from "density-base-ui";
import { RefreshCw } from "lucide-react";
import { useState } from "react";

export default function ChatMessageAnimateExample() {
  const [animationKey, setAnimationKey] = useState(0);

  return (
    <View>
      <ChatMessage animationKey={animationKey} animate author="agent">
        I found three relevant results, each with current information.
      </ChatMessage>
      <Button onClick={() => setAnimationKey((key) => key + 1)}>
        <RefreshCw aria-hidden="true" size={14} />
        Replay animation
      </Button>
    </View>
  );
}

Padding

Padding applies only to user bubbles. User messages use size-derived padding by default; use padding={false} for a flush bubble. Agent messages remain without padding.

No padding
Default padding
import { ChatMessage, View } from "density-base-ui";

export default function ChatMessagePaddingExample() {
  return (
    <View padding={false}>
      <ChatMessage author="user" padding={false}>
        No padding
      </ChatMessage>
      <ChatMessage author="user" padding>
        Default padding
      </ChatMessage>
    </View>
  );
}

Size

ChatMessage inherits the surrounding size when size is omitted. Its body text matches that scope, so sm messages use sm body text. Optional time and actions remain smaller.

Small message
Medium message
import { ChatMessage, View } from "density-base-ui";

export default function ChatMessageSizeExample() {
  return (
    <View>
      <ChatMessage author="agent" size="sm">
        Small message
      </ChatMessage>
      <ChatMessage author="agent" size="md">
        Medium message
      </ChatMessage>
    </View>
  );
}