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

Chat Log

Version 5.2.2GithubStorybookPeer 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.