The content
prop of the <Message>
component is passed to a <Markdown>
component (from react-markdown), which is configured to translate plain text strings into PatternFly <Content>
components and code blocks into PatternFly <CodeBlock>
components.
Messages
Bot messages
Messages from the ChatBot will be marked with an "AI" label to clearly communicate the use of AI to users. The ChatBot can display different content
types, including plain text, code, or a loading animation (via isLoading
).
By default, a date and timestamp is displayed with each message. We recommend using the timestamp
prop in real ChatBots, since it will allow you to set persistent dates and times on messages, even if the messages re-render. You can update timestamp
with a different date and time format as needed.
You can further customize the avatar by applying an additional class or passing PatternFly avatar props to the <Message>
component via avatarProps
.
Message actions
You can add actions to a message, to allow users to interact with the message content. These actions can include:
- Feedback responses that allow users to rate a message as "good" or "bad".
- Copy and share controls that allow users to share the message content with others.
- A listen action, that will read the message content out loud.
Note: The logic for the actions is not built into the component and must be implemented by the consuming application.
Custom message actions
Beyond the standard message actions (good response, bad response, copy, share, or listen), you can add custom actions to a bot message by passing an actions
object to the <Message>
component. This object can contain the following customizations:
ariaLabel
onClick
className
isDisabled
tooltipContent
tooltipContent
tooltipProps
icon
You can apply a clickedAriaLabel
and clickedTooltipContent
once a button is clicked. If either of these props are omitted, their values will default to the ariaLabel
or tooltipContent
supplied.
Message feedback
When a user selects a positive or negative message action, you can display a message feedback card that acknowledges their response and provides space for additional written feedback. These cards can be manually dismissed via the close button and the thank-you card can be configured to time out automatically.
You can see the full feedback flow in the message demos.
The message feedback cards will immediately receive focus by default, but you can remove this behavior by passing focusOnLoad: false
to the <Message>
(as shown in the following examples). For better usability, you should generally keep the default focus behavior.
The following examples demonstrate:
- A basic feedback card. To toggle the text input area, select the Has text area checkbox.
- A thank-you card. To toggle the close button, select the Has close button checkbox.
Message feedback with timeouts
The feedback thank-you message can be configured to time out and automatically close after a period of time. The default time-out period is 8000 ms, but it can be customized via timeout
.
To display the thank-you message in this example, click Show card.
The card will not dismiss within the default time if a user is hovering over it or if it has keyboard focus. Instead, it will dismiss after they remove focus, via timeoutAnimation
, which is 3000 ms by default. You can adjust this duration and set an onTimeout
callback, as well as optional onMouseEnter
and onMouseLeave
callbacks.
For accessibility purposes, be sure to announce when new content appears onscreen. isLiveRegion
is set to true by default on <Message>
so it will make appropriate announcements for you when the thank-you card appears.
Messages with quick responses
You can offer convenient, clickable responses to messages in the form of quick actions. Quick actions are PatternFly labels in a label group, configured to display up to 5 visible labels. Only 1 response can be selected at a time.
To add quick actions, pass quickResponses
to <Message>
. This can be overridden by passing additional <LabelGroup>
props to quickResponseContainerProps
, or additional <Label>
props to quickResponses
.
Messages with sources
If you are using Retrieval-Augmented Generation, you may want to display sources in a message. Passing sources
to <Message>
allows you to paginate between the sources you provide.
The API for a source requires a link at minimum, but we strongly recommend providing a more descriptive title and body description so users have enough context. The title is limited to 1 line and the body is limited to 2 lines.
Messages with quick start tiles
Quick start tiles can be added to messages via the quickStarts
prop. Users can initiate the quick start from a link within the message tile.
The quick start tile displayed below the message is based on the tile included in the PatternFly quick starts extension, but with slightly more limited functionality. For example, it does not track the state of the extension. However, it supports an additional onSelectQuickStart
prop, so that the name of the quick start can be captured on click. This can be used to trigger other behavior in your application, such as launching that quick start in your main UI.
User messages
Messages from users have a different background color to differentiate them from bot messages. You can also display a custom avatar that is uploaded by the user. You can further customize the avatar by applying an additional class or passing PatternFly avatar props to the <Message>
component via avatarProps
.
Custom message content
Caution: Take care when using this feature. It can cause you to stray from accessibility and design best practice standards. If you frequently need add the same component via custom message content, reach out to the PatternFly team. If there's a consistent need for a certain component, we can look into adding native support for additional features.
You can add custom content to specific parts of a <Message>
via the extraContent
prop, including additional components (like timestamps, badges, or custom elements). This prop allows you to create dynamic and reusable elements for various use cases, without changing the default message layout.
File attachments
Messages with attachments
When attachments are shared and displayed in the ChatBot window, users will see a selectable and dismissible message that contains file details in a label. Selecting the file label can open a preview modal, which allows users to view or make edits to the file contents.
The <PreviewAttachment>
component displays a modal with a read-only view of the attached file's contents. Selecting the "edit" button will open the <AttachmentEdit>
component, which provides an interactive environment where users can make changes to the file.
If a displayMode
is not passed to <PreviewAttachment>
or <AttachmentEdit>
, they both default to overlaying the default displayMode
of the <Chatbot>
component.
Note: This example does not actually apply any edits to the attached file. That logic depends on the implementation.
We are using react-dropzone for opening the file dialog and handling drag and drop. It does not process files or provide any way to make HTTP requests to a server. If you need this, react-dropzone suggests filepond or uppy.io.. To handle edge cases, like restricting the number or size of files, you can pass a function to the handleAttach
prop on MessageBar
or onFileDrop
prop in FileDropZone.
Attachment label
When an attachment is successfully uploaded, a label will appear in the message box. There are several label variants that cover different attachment states, including:
- Plain: Default attachment labels, which display the filename and extension.
- Closeable: Attachments that can be dismissed.
- Clickable: Attachments that can be selected, typically to open file details.
- Loading: Attachments that are still being uploaded.
Attachment preview
To allow users to preview the contents of an attachment, load a read-only view of the file contents in a new modal.
Editable attachments
To allow users to edit an attached file, load a new code editor within the ChatBot window. On this screen, you can allow users to edit a file and save changes if they'd like. Return users to the main ChatBot window once they dismiss the editor.
Failed attachment error
When an attachment upload fails, a danger alert is displayed to provide details about the reason for failure.
Props
AttachMenu
Name | Type | Default | Description |
---|---|---|---|
filteredItemsrequired | React.ReactNode | Items in menu | |
handleTextInputChangerequired | (value: string) => void | A callback for when the input value changes. | |
isOpenrequired | boolean | Flag to indicate if menu is opened. | |
onOpenChangerequired | (isOpen: boolean) => void | Callback to change the open state of the menu. Triggered by clicking outside of the menu. | |
togglerequired | DropdownToggleProps | ((toggleRef: React.RefObject<any>) => React.ReactNode) | Toggle to be rendered | |
onOpenChangeKeys | string[] | Keys that trigger onOpenChange, defaults to tab and escape. It is highly recommended to include Escape in the array, while Tab may be omitted if the menu contains non-menu items that are focusable. | |
onSelect | (event?: React.MouseEvent<Element, MouseEvent>, value?: string | number) => void | Function callback called when user selects item. | |
popperProps | ExtendedDropdownPopperProps | undefined | Additional properties to pass to the Popper |
searchInputAriaLabel | string | 'Filter menu items' | Aria label for search input |
searchInputPlaceholder | string | Placeholder for search input |
AttachmentEdit
Name | Type | Default | Description |
---|---|---|---|
coderequired | string | Text shown in code editor | |
fileNamerequired | string | Filename, including extension, of file shown in editor | |
handleModalTogglerequired | (event: React.MouseEvent | MouseEvent | KeyboardEvent) => void | Function that opens and closes modal | |
isModalOpenrequired | boolean | Whether modal is open | |
onCancelrequired | (event: React.MouseEvent | MouseEvent | KeyboardEvent) => void | Function that runs when cancel button is clicked | |
onSaverequired | (event: React.MouseEvent | MouseEvent | KeyboardEvent, code: string) => void | Function that runs when save button is clicked; allows consumers to use the edited code string | |
displayMode | ChatbotDisplayMode | ChatbotDisplayMode.default | Display mode for the Chatbot parent; this influences the styles applied |
title | string | 'Edit attachment' | Title of modal |
FileDetailsProps
Name | Type | Default | Description |
---|---|---|---|
fileNamerequired | string | Name of file, including extension | |
className | string | Class name applied to container | |
fileNameClassName | string | Class name applied to file name | |
languageTestId | string | Custom test id for the component-generated language |
FileDetailsLabelProps
Name | Type | Default | Description |
---|---|---|---|
fileNamerequired | string | Name of file, including extension | |
closeButtonAriaLabel | string | Aria label for close button | |
fileId | string | number | Unique id of file | |
isLoading | boolean | Whether to display loading icon | |
languageTestId | string | Custom test id for the component-generated language | |
onClick | (event: React.MouseEvent, fileName: string, fileId?: string | number) => void | Callback function for when label is clicked | |
onClose | (event: React.MouseEvent, fileName: string, fileId?: string | number) => void | Callback function for when close button is clicked | |
spinnerTestId | string | Custom test id for the loading spinner in the component |
FileDropZone
Name | Type | Default | Description |
---|---|---|---|
onFileDroprequired | (event: DropEvent, data: File[]) => void | When files are dropped or uploaded this callback will be called with all accepted files | |
children | React.ReactNode | Content displayed when the drop zone is not currently in use | |
className | string | Custom classname for the outer dropzone component | |
displayMode | ChatbotDisplayMode | ChatbotDisplayMode.default | Display mode for the Chatbot parent; this influences the styles applied |
infoText | string | 'Maximum file size is 25 MB' | Informational text that shows below the title in the drop zone |
PreviewAttachment
Name | Type | Default | Description |
---|---|---|---|
coderequired | string | Text shown in code editor | |
fileNamerequired | string | Filename, including extension, of file shown in modal | |
handleModalTogglerequired | (event: React.MouseEvent | MouseEvent | KeyboardEvent) => void | Function called when modal is toggled | |
isModalOpenrequired | boolean | Whether modal is open | |
onEditrequired | (event: React.MouseEvent | MouseEvent | KeyboardEvent) => void | Function called when edit button is clicked | |
displayMode | ChatbotDisplayMode | ChatbotDisplayMode.default | Display mode for the Chatbot parent; this influences the styles applied |
onDismiss | (event: React.MouseEvent | MouseEvent | KeyboardEvent) => void | undefined | Function called when dismiss button is clicked |
title | string | 'Preview attachment' | Title of modal |
Message
Name | Type | Default | Description |
---|---|---|---|
avatarrequired | string | Avatar src for the user | |
rolerequired | 'user' | 'bot' | Role of the user sending the message | |
actions | { [key: string]: ActionProps; } | Props for message actions, such as feedback (positive or negative), copy button, share, and listen | |
additionalRehypePlugins | PluggableList | Additional rehype plugins passed from the consumer | |
attachments | MessageAttachment[] | Array of attachments attached to a message | |
avatarProps | Omit<AvatarProps, 'alt'> | Any additional props applied to the avatar, for additional customization | |
botWord | string | Label for the English word "AI," used to tag messages with role "bot" | |
codeBlockProps | { 'aria-label'?: string; className?: string; } | ||
content | string | Message content | |
error | AlertProps | Optional inline error message that can be displayed in the message | |
extraContent | MessageExtraContent | Extra Message content | |
hasRoundAvatar | boolean | Whether avatar is round | |
id | string | Unique id for message | |
innerRef | React.Ref<HTMLDivElement> | Ref applied to message | |
isLiveRegion | boolean | Turns the container into a live region so that changes to content within the Message, such as appending a feedback card, are reliably announced to assistive technology. | |
isLoading | boolean | Set this to true if message is being loaded | |
loadingWord | string | Label for the English "Loading message," displayed to screenreaders when loading a message | |
name | string | Name of the user | |
openLinkInNewTab | boolean | Whether to open links in message in new tab. | |
quickResponseContainerProps | Omit<LabelGroupProps, 'ref'> | Props for quick responses container | |
quickResponses | QuickResponse[] | Props for quick responses | |
quickStarts | { quickStart: QuickStart; onSelectQuickStart: (id?: string) => void; minuteWord?: string; minuteWordPlural?: string; prerequisiteWord?: string; prerequisiteWordPlural?: string; quickStartButtonAriaLabel?: string; className?: string; onClick?: () => void; action?: QuickstartAction; } | Props for QuickStart card | |
sources | SourcesCardProps | Sources for message | |
tableProps | Required<Pick<TableProps, 'aria-label'>> & TableProps | Props for table message. It is important to include a detailed aria-label that describes the purpose of the table. | |
timestamp | string | Timestamp for the message | |
userFeedbackComplete | Omit<UserFeedbackCompleteProps, 'ref'> | Props for user feedback response | |
userFeedbackForm | Omit<UserFeedbackProps, 'ref'> | Props for user feedback card |
MessageExtraContent
Name | Type | Default | Description |
---|---|---|---|
afterMainContent | ReactNode | Content to display after the main content | |
beforeMainContent | ReactNode | Content to display before the main content | |
endContent | ReactNode | Content to display at the end |
ActionProps
Name | Type | Default | Description |
---|---|---|---|
ariaLabel | string | Aria-label for the button | |
className | string | Class name for the button | |
clickedAriaLabel | string | Aria-label for the button, shown when the button is clicked. | |
clickedTooltipContent | string | Content shown in the tooltip when the button is clicked. | |
icon | React.ReactNode | Icon for custom response action | |
isDisabled | boolean | Props to control if the attach button should be disabled | |
onClick | ((event: MouseEvent | React.MouseEvent<Element, MouseEvent> | KeyboardEvent) => void) | undefined | On-click handler for the button | |
ref | React.Ref<HTMLButtonElement> | Ref for response action button | |
tooltipContent | string | Content shown in the tooltip | |
tooltipProps | TooltipProps | Props to control the PF Tooltip component | |
Unknown | string | Id for content controlled by the button, such as the feedback form |
SourcesCardProps
Name | Type | Default | Description |
---|---|---|---|
sourcesrequired | { title?: string; link: string; body?: React.ReactNode | string }[] | Content rendered inside the paginated card | |
className | string | Additional classes for the pagination navigation container. | |
isDisabled | boolean | Flag indicating if the pagination is disabled. | |
ofWord | string | Label for the English word "of". | |
onNextClick | (event: React.SyntheticEvent<HTMLButtonElement>, page: number) => void | Function called when user clicks to navigate to next page. | |
onPreviousClick | (event: React.SyntheticEvent<HTMLButtonElement>, page: number) => void | Function called when user clicks to navigate to previous page. | |
onSetPage | (event: React.MouseEvent | React.KeyboardEvent | MouseEvent, newPage: number) => void | Function called when page is changed. | |
paginationAriaLabel | string | Accessible label for the pagination component. | |
sourceWord | string | Label for the English word "source" | |
sourceWordPlural | string | Plural for sourceWord | |
toNextPageAriaLabel | string | Accessible label for the button which moves to the next page. | |
toPreviousPageAriaLabel | string | Accessible label for the button which moves to the previous page. |
UserFeedbackProps
Name | Type | Default | Description |
---|---|---|---|
onCloserequired | () => void | Callback function for when close button is clicked | |
onSubmitrequired | (selectedResponse?: string, additionalFeedback?: string) => void | Callback function for when form is submitted | |
cancelWord | string | ||
className | string | Additional classes for the pagination navigation container. | |
closeButtonAriaLabel | string | Aria label for close button | |
focusOnLoad | boolean | Whether to focus card on load | |
hasTextArea | boolean | Whether form includes text area | |
headingLevel | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | The heading level to use, default is h1 | |
id | string | Uniquely identifies the card. | |
onTextAreaChange | (event: React.ChangeEvent<HTMLTextAreaElement>, value: string) => void | Callback function for when text area changes | |
quickResponseContainerProps | Omit<LabelGroupProps, 'ref'> | Props for quick responses container | |
quickResponses | QuickResponse[] | Quick responses a user can select | |
submitWord | string | Label for the English word "Submit." | |
textAreaAriaLabel | string | Aria label for text area | |
textAreaPlaceholder | string | Placeholder of text area | |
timestamp | string | Timestamp passed in by Message for more context in aria announcements |
UserFeedbackCompleteProps
Name | Type | Default | Description |
---|---|---|---|
body | string | React.ReactNode | Substitute for the English phrase "You have successfully sent your feedback! Thank you for responding." | |
className | string | Additional classes for the pagination navigation container. | |
closeButtonAriaLabel | string | Aria label for close button | |
focusOnLoad | boolean | Whether to focus card on load | |
id | string | Uniquely identifies the completion card. | |
isLiveRegion | boolean | Flag to indicate if the card is in a live region. | |
onClose | () => void | Callback function for when close button is clicked | |
onMouseEnter | (e: React.MouseEvent<HTMLDivElement>) => void | Callback for when mouse hovers over card | |
onMouseLeave | (e: React.MouseEvent<HTMLDivElement>) => void | Callback for when mouse stops hovering over card | |
onTimeout | () => void | Function to be executed on timeout. Relevant when the timeout prop is set. | |
ouiaId | number | string | Value to overwrite the randomly generated data-ouia-component-id. | |
ouiaSafe | boolean | Set the value of data-ouia-safe. Only set to true when the component is in a static state, i.e. no animations are occurring. At all other times, this value must be false. | |
timeout | number | boolean | If set to true, the timeout is 8000 milliseconds. If a number is provided, card will be dismissed after that amount of time in milliseconds. | |
timeoutAnimation | number | If the user hovers over the card and `timeout` expires, this is how long to wait before finally dismissing the alert. | |
timestamp | string | Timestamp passed in by Message for more context in aria announcements | |
title | string | Substitute for the English phrase "Thank you". |
QuickResponseProps
Name | Type | Default | Description |
---|---|---|---|
quickResponsesrequired | QuickResponse[] | Props for quick responses | |
onSelect | (id: string) => void | Callback when a response is clicked; used in feedback cards | |
quickResponseContainerProps | Omit<LabelGroupProps, 'ref'> | Props for quick responses container |