Skip to contentSkip to navigationSkip to topbar
Paste assistant Assistant
Figma
Star

Chat Log

Version 5.2.1GithubStorybookPeer review pending

Chat log is a collection of components that allow users to read a series of messages over time.

Component preview theme
<ChatLog>
<ChatMessage variant='inbound'>
<ChatBubble>
Hello, what can I help you with?
</ChatBubble>
<ChatMessageMeta aria-label="said by Gibby Radki at 3:35 PM">
<ChatMessageMetaItem>
<Avatar name="Gibby Radki" size="sizeIcon20" />
Gibby Radki ・ 3:35 PM
</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
<ChatMessage variant='outbound'>
<ChatBubble>
Hi! What is your return policy?
</ChatBubble>
<ChatMessageMeta aria-label="said by you at 3:35 PM">
<ChatMessageMetaItem>3:35 PM</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
</ChatLog>

Guidelines

Guidelines page anchor

About Chat Log

About Chat Log page anchor

A Chat Log is a way to display conversations between people and can include complex content like attachments. The chat can be between two or more people. If you are looking for a chat between a human and an AI please refer to AIChatLog.

The Chat Log package includes these main components:

  • ChatLog
  • ChatMessage
  • ChatBubble
  • ChatBookend
  • ChatEvent
  • ChatAttachment
  • ChatMessageMeta

To ensure the chat is accessible, only use the Chat components within a ChatLog component and use ChatMessage to wrap ChatBubbles and ChatMessageMeta components together.

The only other accessibility requirement is providing the ChatMessageMeta a descriptive label via the aria-label React prop.

The ChatLog component has role=”log” which means that any new messages added to it are announced by assistive technology.

A basic message is simply text sent from a chat participant and is built with the ChatMessage and ChatBubble components. It can either be inbound or outbound.

Inbound

Inbound page anchor
Component preview theme
const BasicMessage = () => {
return (
<ChatLog>
<ChatMessage variant='inbound'>
<ChatBubble>
Ahoy!
</ChatBubble>
</ChatMessage>
</ChatLog>
);
};
render(
<BasicMessage />
)
Component preview theme
const BasicMessage = () => {
return (
<ChatLog>
<ChatMessage variant='outbound'>
<ChatBubble>
Howdy!
</ChatBubble>
</ChatMessage>
</ChatLog>
);
};
render(
<BasicMessage />
)

Message with Message Meta

Message with Message Meta page anchor

Use Message Meta to append additional information to a message such as the name of the sender, the time, or a read receipt.

ChatMessageMeta should be a child of ChatMessage so that the text and meta information are correctly grouped together for assistive technologies. It also needs a readable aria-label that summarizes what the meta information says.

Component preview theme
const MessageWithMeta = () => {
return (
<ChatLog>
<ChatMessage variant='inbound'>
<ChatBubble>
Hello, what can I help you with?
</ChatBubble>
<ChatMessageMeta aria-label="said by Gibby Radki 4 minutes ago">
<ChatMessageMetaItem>
<Avatar name="Gibby Radki" size="sizeIcon20" />
Gibby Radki ・ 4 minutes ago
</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
</ChatLog>
);
};
render(
<MessageWithMeta />
)
Component preview theme
const MessageWithMeta = () => {
return (
<ChatLog>
<ChatMessage variant='outbound'>
<ChatBubble>
Will this presentation be recorded?
</ChatBubble>
<ChatMessageMeta aria-label="said by you at 4:27 PM">
<ChatMessageMetaItem>
4:27 PM
</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
</ChatLog>
);
};
render(
<MessageWithMeta />
)

A message can include an attachment. If sent with additional text, the attachment should be in its own ChatBubble.

Component preview theme
const MessageWithAttachment = () => {
return (
<ChatLog>
<ChatMessage variant='inbound'>
<ChatBubble>
<ChatAttachment attachmentIcon={<DownloadIcon decorative />}>
<ChatAttachmentLink href="#">receipt.pdf</ChatAttachmentLink>
<ChatAttachmentDescription>9 MB</ChatAttachmentDescription>
</ChatAttachment>
</ChatBubble>
</ChatMessage>
</ChatLog>
);
};
render(
<MessageWithAttachment />
)
Component preview theme
const MessageWithAttachment = () => {
return (
<ChatLog>
<ChatMessage variant='outbound'>
<ChatBubble>
<ChatAttachment attachmentIcon={<DownloadIcon decorative />}>
<ChatAttachmentLink href="#">document-FINAL.doc</ChatAttachmentLink>
<ChatAttachmentDescription>123 MB</ChatAttachmentDescription>
</ChatAttachment>
</ChatBubble>
</ChatMessage>
</ChatLog>
);
};
render(
<MessageWithAttachment />
)

ChatMessages can contain multiple ChatBubbles and ChatMessageMetas.

Component preview theme
const ComplexMessage = () => {
return (
<ChatLog>
<ChatMessage variant='inbound'>
<ChatBubble>
I have a copy of the receipt, can you print it?
</ChatBubble>
<ChatBubble>
<ChatAttachment attachmentIcon={<DownloadIcon decorative />}>
<ChatAttachmentLink href="#">receipt.pdf</ChatAttachmentLink>
<ChatAttachmentDescription>9 MB</ChatAttachmentDescription>
</ChatAttachment>
</ChatBubble>
<ChatMessageMeta aria-label="said by Gibby Radki at 11:27 AM">
<ChatMessageMetaItem>
<Avatar name="Gibby Radki" size="sizeIcon20" />
Gibby Radki ・ 11:27 AM
</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
</ChatLog>
);
};
render(
<ComplexMessage />
)
Component preview theme
const ComplexMessage = () => {
return (
<ChatLog>
<ChatMessage variant='outbound'>
<ChatBubble>
Here is the document:
</ChatBubble>
<ChatBubble>
<ChatAttachment attachmentIcon={<DownloadIcon decorative />}>
<ChatAttachmentLink href="#">document-FINAL.doc</ChatAttachmentLink>
<ChatAttachmentDescription>123 MB</ChatAttachmentDescription>
</ChatAttachment>
</ChatBubble>
<ChatMessageMeta aria-label="said by you at 11:27 AM">
<ChatMessageMetaItem>11:27 AM</ChatMessageMetaItem>
</ChatMessageMeta>
<ChatMessageMeta aria-label="(read)">
<ChatMessageMetaItem>Read</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
</ChatLog>
);
};
render(
<ComplexMessage />
)

Chat Events are for things that can happen during the chat, like someone joining or the chat transferring to a different agent.

Component preview theme
const BasicChatEvent = () => {
return (
<ChatLog>
<ChatEvent>
<strong>Gibby Radki</strong> has joined the chat ・ 11:56 AM
</ChatEvent>
</ChatLog>
);
};
render(
<BasicChatEvent />
)

Chat Bookends are for when the chat starts, ends, and the day when the chat spans multiple days.

Component preview theme
const ChatStartedBookend = () => {
return (
<ChatLog>
<ChatBookend>
<ChatBookendItem>Today</ChatBookendItem>
<ChatBookendItem>
<strong>Chat Started</strong> ・ 3:34pm
</ChatBookendItem>
</ChatBookend>
</ChatLog>
);
};
render(
<ChatStartedBookend />
)

This example combines all the separate features displayed previously into one example. It shows how all the features work together harmoniously through composition.

Component preview theme
const SampleChat = () => {
return (
<Box maxHeight='size40'>
<ChatLog>
<ChatBookend>
<ChatBookendItem>Yesterday</ChatBookendItem>
<ChatBookendItem>
<strong>Chat Started</strong>・3:34 PM
</ChatBookendItem>
</ChatBookend>
<ChatEvent>
<strong>Gibby Radki</strong> has joined the chat・3:34 PM
</ChatEvent>
<ChatMessage variant='inbound'>
<ChatBubble>
Hello, what can I help you with?
</ChatBubble>
<ChatMessageMeta aria-label="said by Gibby Radki at 3:35 PM">
<ChatMessageMetaItem>
<Avatar name="Gibby Radki" size="sizeIcon20" />
Gibby Radki ・ 3:35 PM
</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
<ChatMessage variant='outbound'>
<ChatBubble>
Hi! What is your return policy?
</ChatBubble>
<ChatMessageMeta aria-label="said by you at 3:35 PM">
<ChatMessageMetaItem>3:35 PM</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
<ChatMessage variant='inbound'>
<ChatBubble>
You have 30 days to send your items back. Here is the full policy if you would like to read more.
</ChatBubble>
<ChatBubble>
<ChatAttachment attachmentIcon={<DownloadIcon decorative />}>
<ChatAttachmentLink href="#">RETURN_POLICY.pdf</ChatAttachmentLink>
<ChatAttachmentDescription>17 MB</ChatAttachmentDescription>
</ChatAttachment>
</ChatBubble>
<ChatMessageMeta aria-label="said by Gibby Radki at 3:37 PM">
<ChatMessageMetaItem>
<Avatar name="Gibby Radki" size="sizeIcon20" />
Gibby Radki ・ 3:37 PM
</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
<ChatMessage variant='outbound'>
<ChatBubble>
Thank you
</ChatBubble>
<ChatMessageMeta aria-label="said by you at 3:40 PM">
<ChatMessageMetaItem>3:40 PM</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
<ChatBookend>
<ChatBookendItem>Today</ChatBookendItem>
</ChatBookend>
<ChatMessage variant='outbound'>
<ChatBubble>
I have shipped the item back, how long will it take to get the refund?
</ChatBubble>
<ChatMessageMeta aria-label="said by you at 11:27 AM">
<ChatMessageMetaItem>11:27 AM</ChatMessageMetaItem>
</ChatMessageMeta>
<ChatMessageMeta aria-label="(read)">
<ChatMessageMetaItem>Read</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
<ChatMessage variant='inbound'>
<ChatBubble>
You should recieve the refund within 10 days.
</ChatBubble>
<ChatMessageMeta aria-label="said by Gibby Radki at 11:29 AM">
<ChatMessageMetaItem>
<Avatar name="Gibby Radki" size="sizeIcon20" />
Gibby Radki ・ 11:29 AM
</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
<ChatMessage variant='inbound'>
<ChatBubble>
Do you need help with anything else?
</ChatBubble>
<ChatMessageMeta aria-label="said by Gibby Radki at 11:36 AM">
<ChatMessageMetaItem>
<Avatar name="Gibby Radki" size="sizeIcon20" />
Gibby Radki ・ 11:36 AM
</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
<ChatBookend>
<ChatBookendItem>
<strong>Chat Ended</strong>・11:45 AM
</ChatBookendItem>
</ChatBookend>
</ChatLog>
</Box>
);
};
render(
<SampleChat />
)

The useChatLogger hook provides a hook based approach to managing chat state. It is best used with the <ChatLogger /> component.

useChatLogger returns 4 things:

  • An array of chats.
  • A push method used to add a chat, optionally with a custom ID
  • A pop method used to remove a chat, optionally via its ID.
  • A clear method used to remove all chats.
ChatLogger component
ChatLogger component page anchor

The <ChatLogger /> component handles rendering the chats it is passed via props. It handles how chats enter and leave the UI.

const { chats }= useChatLogger();
return <ChatLogger chats={chats} />;
Adding and removing a chat
Adding and removing a chat page anchor

You can push or pop a chat based on an action or event. In this example it's based on a button click:

Component preview theme
const chatFactory = ([ message, variant, metaLabel, meta ]) => {
const time = new Date(0).toLocaleString(
'en-US',
{ hour: 'numeric', minute: 'numeric', timeZone: 'UTC', hour12: true }
)
return {
variant,
content: (
<ChatMessage variant={variant}>
<ChatBubble>{message}</ChatBubble>
<ChatMessageMeta aria-label={metaLabel + time}>
<ChatMessageMetaItem>{meta + time}</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
)
}
};
const chatTemplates = [
["Hello", "inbound", "said by Gibby Radki at ", "Gibby Radki・"],
["Hi there", "outbound", "said by you at ", ""],
["Greetings", "inbound", "said by Gibby Radki at ", "Gibby Radki・"],
["Good to meet you", "outbound", "said by you at ", ""]
];
const ChatLoggerExample = () => {
const [templateIdx, setTemplateIdx] = React.useState(2);
const { chats, push, pop, clear } = useChatLogger(
chatFactory(chatTemplates[0]),
chatFactory(chatTemplates[1])
);
const pushChat = () => {
const template = chatTemplates[templateIdx];
push(chatFactory(template));
setTemplateIdx((idx) => ++idx % chatTemplates.length);
}
const popChat = () => {
pop();
setTemplateIdx((idx) => idx === 0 ? idx : --idx % chatTemplates.length);
}
return(
<Stack orientation="vertical">
<ButtonGroup>
<Button variant="primary" onClick={pushChat}>
Push Chat
</Button>
<Button variant="primary" onClick={popChat}>
Pop Chat
</Button>
<Button variant="primary" onClick={clear}>
Clear Chat
</Button>
</ButtonGroup>
<ChatLogger chats={chats} />
</Stack>
)
}
render(<ChatLoggerExample />);

Keep content as concise as possible given the space constraints.

To convey an error related to whether a message was sent, use Help Text inside the Message Meta. Limit the message to a single sentence and focus on how the user can resolve the issue. Offer a link-style retry button when applicable.

To convey an error related to other actions taken in the Chat Log, like a file upload validation error, use a Toast at the top of the individual chat window.

To convey an error that applies to the whole page, not just a particular Chat Log, use a page-level Callout or Alert.