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.
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.
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.
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.
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.
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>
);
}| Prop | Values | Required | Default | Behavior | Description |
|---|---|---|---|---|---|
actions | React.ReactNode | Not required | — | — | — |
animate | false, true | Not required | — | — | — |
animationKey | React.Key | Not required | — | — | — |
author | user, agent | Required | — | Attribute: data-dn-author | — |
padding | false, true | Not required | true | Attribute: data-dn-padding | — |
size | sm, md | Not required | — | Attribute: data-dn-size | — |
time | React.ReactNode | Not required | — | — | — |
This component also accepts props from native APIs. They are passed through and intentionally kept out of this focused Density API table.