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

AI Chat Log

Version 1.0.0GithubStorybook

An AI Chat Log is a collection of AI Chat components for displaying conversations between a human and an AI bot.

Component preview theme
<AIChatLog>
<AIChatMessage variant="user">
<AIChatMessageAuthor aria-label="You said at 2:36pm">Gibby Radki</AIChatMessageAuthor>
<AIChatMessageBody>
What does the SMS delivery error code 30003 mean?
</AIChatMessageBody>
</AIChatMessage>
<AIChatMessage variant="bot">
<AIChatMessageAuthor aria-label="AI said">Good Bot</AIChatMessageAuthor>
<AIChatMessageBody>
Here is what I found, error code 30003 means: The destination phone is unavailable or turned off, or it may be a landline or phone that doesn't support SMS.
</AIChatMessageBody>
</AIChatMessage>
</AIChatLog>

Guidelines

Guidelines page anchor

About AI Chat Log

About AI Chat Log page anchor

An AI Chat Log is a way to display conversations between a user and AI. If you are looking for a chat between 2 or more humans, please refer to Chat Log.

The AI Chat Log package includes these main components:

  • AIChatLog
  • AIChatMessage
  • AIChatMessageAuthor
  • AIChatMessageBody
  • AIChatMessageActionGroup
  • AIChatMessageActionCard
  • AIChatMessageLoading

To ensure the chat is accessible, only use the AI Chat components within an AIChatLog component and use AIChatMessage to wrap AIChatMessageBody, AIChatMessageActionGroup and components together.

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

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

A message must include the author and body. Any message text from a user or a bot must be contained within the AIChatMessageBody component. Due to lengthy AI responses, the chat layout is top-down.

Bot

Bot page anchor
Component preview theme
const BasicMessage = () => {
return (
<AIChatLog>
<AIChatMessage variant="bot">
<AIChatMessageAuthor aria-label="AI said">Good Bot</AIChatMessageAuthor>
<AIChatMessageBody>
Here is what I found, error code 30003 means: The destination phone is unavailable or turned off, or it may be a landline or phone that doesn't support SMS.
</AIChatMessageBody>
</AIChatMessage>
</AIChatLog>
);
};
render(
<BasicMessage />
)
Component preview theme
const BasicMessage = () => {
return (
<AIChatLog>
<AIChatMessage variant="user">
<AIChatMessageAuthor aria-label="You said at 2:36pm">Gibby Radki</AIChatMessageAuthor>
<AIChatMessageBody>
I would like some information on twilio error codes for undelivered messages
</AIChatMessageBody>
</AIChatMessage>
</AIChatLog>
);
};
render(
<BasicMessage />
)

The AIChatMessageBody component has two sizes, size="default" and size="fullScreen". The fullScreen size is used where the ChatLog is displayed in the full width of the page where larger font size is needed.

Component preview theme
<AIChatLog>
<AIChatMessage variant="user">
<AIChatMessageAuthor aria-label="You said">Gibby Radki</AIChatMessageAuthor>
<AIChatMessageBody size="default">
I'm a message that should be displayed in compact elements
</AIChatMessageBody>
</AIChatMessage>
<AIChatMessage variant="user">
<AIChatMessageAuthor aria-label="You said">Gibby Radki</AIChatMessageAuthor>
<AIChatMessageBody size="fullScreen">
I'm a message that will be displayed in full screen width
</AIChatMessageBody>
</AIChatMessage>
</AIChatLog>

Message actions can be used to provide quick responses or actions to the user.

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

Each item within AIChatMessageActionGroup should be wrapped with AIChatMessageActionCard. It is recommended to use reset button variants for content within AIChatMessageActionCard.

Actions can still be added in AIChatMessageBody which are returned from the AI response.

Feedback in AIChatMessageActionCard

Feedback in AIChatMessageActionCard page anchor
Component preview theme
const MessageWithFeedback = () => {
return (
<AIChatLog>
<AIChatMessage variant="bot">
<AIChatMessageAuthor aria-label="AI said">Good Bot</AIChatMessageAuthor>
<AIChatMessageBody>
Here is what I found, error code 30003 means: The destination phone is unavailable or turned off, or it may be a landline or phone that doesn't support SMS.
</AIChatMessageBody>
<AIChatMessageActionGroup>
<AIChatMessageActionCard aria-label="Feedback form">
Is this helpful?
<Button variant="reset" size="reset" aria-label="this is a helpful response">
<ThumbsUpIcon decorative={false} title="like result" />
</Button>
<Button variant="reset" size="reset">
<ThumbsDownIcon decorative={false} title="dislike result" aria-label="this is not a helpful response" />
</Button>
</AIChatMessageActionCard>
<AIChatMessageActionCard aria-label="Rewrite and copy buttons">
<Button variant="reset" size="reset">
<RefreshIcon decorative={true}/> Rewrite
</Button>
<Button variant="reset" size="reset">
<CopyIcon decorative={true}/> Copy
</Button>
</AIChatMessageActionCard>
</AIChatMessageActionGroup>
</AIChatMessage>
</AIChatLog>
);
};
render(
<MessageWithFeedback />
)

Buttons in AIChatMessageBody from AI Response

Buttons in AIChatMessageBody from AI Response page anchor
Component preview theme
const MessageWithFeedback = () => {
return (
<AIChatLog>
<AIChatMessage variant="bot">
<AIChatMessageAuthor aria-label="AI said">Good Bot</AIChatMessageAuthor>
<AIChatMessageBody>
<Paragraph>Below is a list of actions that can be taken with flex wrapping supported:</Paragraph>
<ButtonGroup>
<Button variant="secondary" size="rounded_small" onClick={() => {}} >
View Logs
</Button>
<Button variant="secondary" size="rounded_small" onClick={() => {}}>
Run Diagnostics
</Button>
<Button variant="secondary" size="rounded_small" onClick={() => {}}>
Submit Bug Report
</Button>
</ButtonGroup>
</AIChatMessageBody>
</AIChatMessage>
</AIChatLog>
);
};
render(
<MessageWithFeedback />
)

Use the AIChatMessageLoading component to indicate that the bot is typing or processing a response. During this time no user input should be accepted. No new messages should be added to a chat until the AI operation is finished processing.

The SkeletonLoader lengths vary on each render to give a more natural pending message body interaction.

Component preview theme
const MessageWithLoading = () => {
return (
<AIChatLog>
<AIChatMessage variant="bot">
<AIChatMessageAuthor aria-label="AI said" bot>
Good Bot
</AIChatMessageAuthor>
<AIChatMessageBody>
<AIChatMessageLoading />
</AIChatMessageBody>
</AIChatMessage>
</AIChatLog>
);
};
render(
<MessageWithLoading />
)

Loading with Stop Button

Loading with Stop Button page anchor
Component preview theme
const MessageWithLoadingAndStop = () => {
return (
<AIChatLog>
<AIChatMessage variant="bot">
<AIChatMessageAuthor aria-label="AI said" bot>
Good Bot
</AIChatMessageAuthor>
<AIChatMessageBody>
<AIChatMessageLoading onStopLoading={() => {}} />
</AIChatMessageBody>
</AIChatMessage>
</AIChatLog>
);
};
render(
<MessageWithLoadingAndStop />
)

AIChatMessageAuthor can utilize custom icons by passing an icon to the prop avatarIcon or an image to the avatarSrc prop.

Component preview theme
const AvatarExample = () => {
return (
<AIChatLog>
<AIChatMessage variant="user">
<AIChatMessageAuthor avatarIcon={LogoTwilioIcon} aria-label="You said">Gibby Radki</AIChatMessageAuthor>
</AIChatMessage>
<AIChatMessage variant="user">
<AIChatMessageAuthor avatarSrc={Logo.src} aria-label="You said">Gibby Radki</AIChatMessageAuthor>
</AIChatMessage>
</AIChatLog>
);
};
render(
<AvatarExample />
)

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 AIChatLogExample = () => {
return (
<AIChatLog>
<AIChatMessage variant="user">
<AIChatMessageAuthor aria-label="You said">Gibby Radki</AIChatMessageAuthor>
<AIChatMessageBody>
Hi, I'm getting errors codes when sending an SMS.
</AIChatMessageBody>
</AIChatMessage>
<AIChatMessage variant="bot">
<AIChatMessageAuthor aria-label="AI said">Good Bot</AIChatMessageAuthor>
<AIChatMessageBody>
<Paragraph>Error codes can be returned from various parts of the process. What error codes are you encountering?</Paragragh>
<ButtonGroup>
<Button variant="secondary" size="rounded_small" onClick={() => {}} >
21608
</Button>
<Button variant="secondary" size="rounded_small" onClick={() => {}}>
30007
</Button>
<Button variant="secondary" size="rounded_small" onClick={() => {}}>
30009
</Button>
</ButtonGroup>
</AIChatMessageBody>
</AIChatMessage>
<AIChatMessage variant="bot">
<AIChatMessageAuthor aria-label="AI said">Good Bot</AIChatMessageAuthor>
<AIChatMessageBody>
Error 21608 means you're trying to send a message from an unverified number. Is your number verified in your Twilio account?
</AIChatMessageBody>
<AIChatMessageActionGroup>
<AIChatMessageActionCard aria-label="Feedback form">
Is this helpful?
<Button variant="reset" size="reset" aria-label="this is a helpful response">
<ThumbsUpIcon decorative={false} title="like result" />
</Button>
<Button variant="reset" size="reset">
<ThumbsDownIcon decorative={false} title="dislike result" aria-label="this is not a helpful response"/>
</Button>
</AIChatMessageActionCard>
</AIChatMessageActionGroup>
</AIChatMessage>
<AIChatMessage variant="user">
<AIChatMessageAuthor aria-label="You said" bot>
Gibby Radki
</AIChatMessageAuthor>
<AIChatMessageBody>
No, how do I verify it?
</AIChatMessageBody>
</AIChatMessage>
<AIChatMessage variant="bot">
<AIChatMessageAuthor aria-label="AI said" bot>
Good Bot
</AIChatMessageAuthor>
<AIChatMessageBody>
<AIChatMessageLoading onStopLoading={() => {}} />
</AIChatMessageBody>
</AIChatMessage>
</AIChatLog>
);
};
render(
<AIChatLogExample />
)

The useAIChatLogger hook provides a hook-based approach to managing AI chat state. It is best used with the <AIChatLogger /> component.

useAIChatLogger returns 4 things:

  • An array of aiChats.
  • 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.
AIChatLogger component
AIChatLogger component page anchor

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

const { aiChats } = useAIChatLogger();
return <AIChatLogger aiChats={aiChats} />;
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 aiChatFactory = ([ message, variant, metaLabel, meta ]) => {
const time = new Date(0).toLocaleString(
'en-US',
{ hour: 'numeric', minute: 'numeric', timeZone: 'UTC', hour12: true }
)
return {
variant,
content: (
<AIChatMessage variant={variant}>
<AIChatMessageAuthor aria-label={metaLabel + time}>{meta}</AIChatMessageAuthor>
<AIChatMessageBody>
{message}
</AIChatMessageBody>
</AIChatMessage>
)
}
};
const chatTemplates = [
["Hello", "user", "You said at ", "Gibby Radki"],
["Hi there", "bot", "AI said at ", "Good Bot"],
["Greetings", "user", "You said at ", "Gibby Radki"],
["Good to meet you", "bot", "AI said at ", "Good Bot"]
];
const AIChatLoggerExample = () => {
const [templateIdx, setTemplateIdx] = React.useState(2);
const { aiChats, push, pop, clear } = useAIChatLogger(
aiChatFactory(chatTemplates[0]),
aiChatFactory(chatTemplates[1])
);
const [loading, setLoading] = React.useState(false);
const pushChat = () => {
const template = chatTemplates[templateIdx];
setTemplateIdx((idx) => ++idx % chatTemplates.length);
const chat = aiChatFactory(template);
if (template[1] === "bot") {
const id = uid(chat.content);
setLoading(true);
push({
id,
variant: template[1],
content: (
<AIChatMessage variant="bot">
<AIChatMessageAuthor aria-label="AI said">Good Bot</AIChatMessageAuthor>
<AIChatMessageBody>
<AIChatMessageLoading />
</AIChatMessageBody>
</AIChatMessage>
),
});
setTimeout(() => {
pop(id);
setLoading(false);
push(chat);
}, 1000);
} else {
push(chat);
}
}
const popChat = () => {
pop();
setTemplateIdx((idx) => idx === 0 ? idx : --idx % chatTemplates.length);
}
return(
<Stack orientation="vertical">
<ButtonGroup>
<Button variant="primary" disabled={loading} onClick={pushChat}>
Push Chat
</Button>
<Button variant="primary" disabled={loading} onClick={popChat}>
Pop Chat
</Button>
<Button variant="primary" disabled={loading} onClick={clear}>
Clear Chat
</Button>
</ButtonGroup>
<AIChatLogger aiChats={aiChats} />
</Stack>
)
}
render(<AIChatLoggerExample />);

Keep any generated responses from the AI contained in the AIChatMessageBody component. Each chat message should only have one AIChatMessageBody component.