<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. 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.
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 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.
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.