<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>
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.
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.
const BasicMessage = () => {return (<ChatLog><ChatMessage variant='inbound'><ChatBubble>Ahoy!</ChatBubble></ChatMessage></ChatLog>);};render(<BasicMessage />)
const BasicMessage = () => {return (<ChatLog><ChatMessage variant='outbound'><ChatBubble>Howdy!</ChatBubble></ChatMessage></ChatLog>);};render(<BasicMessage />)
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.
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 />)
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.
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 />)
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.
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 />)
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.
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.
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.
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 3 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.
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} />;
You can push or pop a chat based on an action or event. In this example it's based on a button click:
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.