Skip to content

Commit

Permalink
Address a11y and design feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
rebeccaalpert committed Jan 20, 2025
1 parent ddfffae commit 1f52d24
Show file tree
Hide file tree
Showing 20 changed files with 411 additions and 253 deletions.
Original file line number Diff line number Diff line change
@@ -1,176 +1,71 @@
import React from 'react';
import Message from '@patternfly/chatbot/dist/dynamic/Message';
import patternflyAvatar from './patternfly_avatar.jpg';
import { Checkbox, FormGroup, Stack } from '@patternfly/react-core';

export const MessageWithFeedbackExample: React.FunctionComponent = () => {
const [showUserFeedbackForm, setShowUserFeedbackForm] = React.useState(false);
const [showCompletionForm, setShowCompletionForm] = React.useState(false);
const [launchButton, setLaunchButton] = React.useState<string>();
const positiveRef = React.useRef<HTMLButtonElement>(null);
const negativeRef = React.useRef<HTMLButtonElement>(null);
const feedbackId = 'user-feedback-form';
const completeId = 'user-feedback-received';

const getCurrentCard = () => {
if (showUserFeedbackForm) {
return feedbackId;
}
if (showCompletionForm) {
return completeId;
}
};

const isExpanded = showUserFeedbackForm || showCompletionForm;

const focusLaunchButton = () => {
if (launchButton === 'positive') {
positiveRef.current?.focus();
}
if (launchButton === 'negative') {
negativeRef.current?.focus();
}
};
const [hasCloseButton, setHasCloseButton] = React.useState(true);
const [hasTextArea, setHasTextArea] = React.useState(false);

return (
<>
<Message
isLiveRegion
name="Bot"
role="bot"
avatar={patternflyAvatar}
content="Bot message with user feedback flow; click on a message action to launch the feedback flow. Click submit to see the thank you message."
actions={{
positive: {
onClick: () => {
setShowUserFeedbackForm(true);
setShowCompletionForm(false);
setLaunchButton('positive');
},
/* These are important for accessibility */
'aria-expanded': isExpanded,
'aria-controls': getCurrentCard(),
isClicked: launchButton === 'positive',
ref: positiveRef
},
negative: {
onClick: () => {
setShowUserFeedbackForm(true);
setShowCompletionForm(false);
setLaunchButton('negative');
},
/* These are important for accessibility */
'aria-expanded': isExpanded,
'aria-controls': getCurrentCard(),
isClicked: launchButton === 'negative',
ref: negativeRef
}
}}
userFeedbackForm={
showUserFeedbackForm
? /* eslint-disable indent */
{
quickResponses: [
{ id: '1', content: 'Correct' },
{ id: '2', content: 'Easy to understand' },
{ id: '3', content: 'Complete' }
],
onSubmit: (quickResponse, additionalFeedback) => {
alert(`Selected ${quickResponse} and received the additional feedback: ${additionalFeedback}`);
setShowUserFeedbackForm(false);
setShowCompletionForm(true);
focusLaunchButton();
},
hasTextArea: true,
onClose: () => {
setShowUserFeedbackForm(false);
focusLaunchButton();
},
id: feedbackId
}
: undefined
/* eslint-enable indent */
}
userFeedbackComplete={
showCompletionForm
? /* eslint-disable indent */
{
onClose: () => {
setShowCompletionForm(false);
focusLaunchButton();
},
id: completeId
}
: undefined
/* eslint-enable indent */
}
/>
<Message
name="Bot"
role="bot"
avatar={patternflyAvatar}
content="Bot message with feedback form only"
userFeedbackForm={{
quickResponses: [
{ id: '1', content: 'Correct' },
{ id: '2', content: 'Easy to understand' },
{ id: '3', content: 'Complete' }
],
onSubmit: (quickResponse, additionalFeedback) =>
alert(`Selected ${quickResponse} and received the additional feedback: ${additionalFeedback}`),
hasTextArea: true,
// eslint-disable-next-line no-console
onClose: () => console.log('closed feedback form'),
focusOnLoad: false
}}
/>
<Message
name="Bot"
role="bot"
avatar={patternflyAvatar}
content="Bot message with feedback form that doesn't include text area"
userFeedbackForm={{
quickResponses: [
{ id: '1', content: 'Correct' },
{ id: '2', content: 'Easy to understand' },
{ id: '3', content: 'Complete' }
],
onSubmit: (quickResponse) => alert(`Selected ${quickResponse}`),
<Stack hasGutter>
<FormGroup role="radiogroup" isInline fieldId="feedback-card" label="Variant">
<Checkbox
isChecked={hasTextArea}
onChange={() => {
setHasTextArea(!hasTextArea);
}}
name="basic-inline-radio"
label="Has text area"
id="has-text-area"
/>
</FormGroup>
<Message
name="Bot"
role="bot"
avatar={patternflyAvatar}
content="Bot message with feedback form only"
userFeedbackForm={{
quickResponses: [
{ id: '1', content: 'Correct' },
{ id: '2', content: 'Easy to understand' },
{ id: '3', content: 'Complete' }
],
onSubmit: (quickResponse, additionalFeedback) =>
alert(`Selected ${quickResponse} and received the additional feedback: ${additionalFeedback}`),
hasTextArea,
// eslint-disable-next-line no-console
onClose: () => console.log('closed feedback form'),
focusOnLoad: false
}}
/>
</Stack>
<Stack hasGutter>
<FormGroup role="radiogroup" isInline fieldId="feedback-thank-you" label="Variant">
<Checkbox
isChecked={hasCloseButton}
onChange={() => {
setHasCloseButton(!hasCloseButton);
}}
name="basic-inline-radio"
label="Has close button"
id="has-close"
/>
</FormGroup>
<Message
name="Bot"
role="bot"
avatar={patternflyAvatar}
content="Bot message with completion message"
// eslint-disable-next-line no-console
onClose: () => console.log('closed feedback form'),
focusOnLoad: false
}}
/>
<Message
name="Bot"
role="bot"
avatar={patternflyAvatar}
content="Bot message with feedback form without close button"
userFeedbackForm={{
quickResponses: [
{ id: '1', content: 'Correct' },
{ id: '2', content: 'Easy to understand' },
{ id: '3', content: 'Complete' }
],
onSubmit: (quickResponse, additionalFeedback) =>
alert(`Selected ${quickResponse} and received the additional feedback: ${additionalFeedback}`),
focusOnLoad: false
}}
/>
<Message
name="Bot"
role="bot"
avatar={patternflyAvatar}
content="Bot message with completion message"
// eslint-disable-next-line no-console
userFeedbackComplete={{ onClose: () => console.log('closed completion message'), focusOnLoad: false }}
/>
<Message
name="Bot"
role="bot"
avatar={patternflyAvatar}
content="Bot message with completion message without close button"
userFeedbackComplete={{ focusOnLoad: false }}
/>
userFeedbackComplete={{
// eslint-disable-next-line no-console
onClose: hasCloseButton ? () => console.log('closed completion message') : undefined,
focusOnLoad: false
}}
/>
</Stack>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -102,33 +102,29 @@ You can apply a `clickedAriaLabel` and `clickedTooltipContent` once a button is

### Message feedback

When a user selects a positive or negative [message action](#message-actions), 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 or be [configured to time out automatically](/patternfly-ai/chatbot/messages#message-feedback-with-timeouts).
When a user selects a positive or negative [message action](#message-actions), 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](/patternfly-ai/chatbot/messages#message-feedback-with-timeouts).
<br /><br />
The message feedback card will immediately receive focus by default, but you 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.
You can see a demo of the full feedback flow [in the demos section](http://localhost:8006/patternfly-ai/chatbot/messages/demo#message-feedback)
<br /><br />
The message feedback cards will immediately receive focus by default, but you 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.
<br /><br />
The following examples demonstrate:

- A full feedback flow, which accepts written feedback submission and displays the thank you card.
- A basic card.
- A basic card without text input.
- A card without a close button.
- Thank-you cards, with and without a close button.

The full feedback flow example also demonstrates how to handle focus appropriately for accessibility. The card will be focused when it appears in the DOM. When the card closes, place the focus back on the launching button. You can also add `aria-expanded` and `aria-controls` attributes to the feedback buttons to provide additional context on what the button controls.
<br /><br />
It is also important to announce when new content appears onscreen for accessibility purposes. If you set `isLiveRegion` to true on `<Message>`, it will make appropriate announcements for you when the feedback card appears.

```js file="./MessageWithFeedback.tsx"

```

### Message feedback with timeouts

The feedback card and 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`.
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`.
<br /><br />
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.
<br /><br />
For accessibility purposes, be sure to announce when new content appears onscreen. If you set `isLiveRegion` to `true` for a `<Message>`, it will make appropriate announcements for you when the feedback card appears.
For accessibility purposes, be sure to announce when new content appears onscreen. `isLiveRegion` is set to true by default on `<Message>` soit will make appropriate announcements for you when the thank-you card appears.

```js file="./MessageWithFeedbackTimeout.tsx"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,20 @@ import patternflyAvatar from '../Messages/patternfly_avatar.jpg';

## Demos

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

The following example demonstrates a full feedback flow, which accepts written feedback submission and displays a thank you card.

It also demonstrates how to handle focus appropriately for accessibility. The card will be focused when it appears in the DOM. When the card closes, place the focus back on the launching button. You can also add aria-expanded and aria-controls attributes to the feedback buttons to provide additional context on what the button controls.

It is also important to announce when new content appears onscreen for accessibility purposes. isLiveRegion is set to true by default on <Message> so it will make appropriate announcements for you when the feedback card appears.

```js file="./Feedback.tsx"

```

### Attach via upload button in message bar

This demo displays unique attachment features, including:
Expand Down
Loading

0 comments on commit 1f52d24

Please sign in to comment.