Skip to content

Commit 5d2e95f

Browse files
lexi-taylorOEvgeny
andauthored
Feedback form aria-label computed value does not match on screen text (#5567)
* add aria label to feedback form send box * add changelog entry * add eslint disables * Update packages/component/src/Attachment/Text/private/Markdownable.tsx Co-authored-by: Eugene <EOlonov@gmail.com> * fix issues where textarea was repeating * fix test * fix duplication in narrator * fix tests * update changelog --------- Co-authored-by: Eugene <EOlonov@gmail.com>
1 parent 1b23c01 commit 5d2e95f

File tree

8 files changed

+42
-11
lines changed

8 files changed

+42
-11
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ Notes: web developers are advised to use [`~` (tilde range)](https://github.com/
9898
- Added support of [contentless activity in livestream](https://github.com/microsoft/BotFramework-WebChat/blob/main/docs/LIVESTREAMING.md#scenario-3-interim-activities-with-no-content), in PR [#5430](https://github.com/microsoft/BotFramework-WebChat/pull/5430), by [@compulim](https://github.com/compulim)
9999
- Added sliding dots typing indicator in Fluent theme, in PR [#5447](https://github.com/microsoft/BotFramework-WebChat/pull/5447) and PR [#5448](https://github.com/microsoft/BotFramework-WebChat/pull/5448), by [@compulim](https://github.com/compulim)
100100
- (Experimental) Add an ability to pass `completion` prop into Fluent send box and expose the component, in PR [#5466](https://github.com/microsoft/BotFramework-WebChat/pull/5466), by [@OEvgeny](https://github.com/OEvgeny)
101-
- Added feedback form for like/dislike button when `feedbackActionsPlacement` is `"activity-actions"`, in PR [#5460](https://github.com/microsoft/BotFramework-WebChat/pull/5460), PR [#5469](https://github.com/microsoft/BotFramework-WebChat/pull/5469), PR [5470](https://github.com/microsoft/BotFramework-WebChat/pull/5470) and PR [#5501](https://github.com/microsoft/BotFramework-WebChat/pull/5501) by [@lexi-taylor](https://github.com/lexi-taylor) and [@OEvgeny](https://github.com/OEvgeny)
101+
- Added feedback form for like/dislike button when `feedbackActionsPlacement` is `"activity-actions"`, in PR [#5460](https://github.com/microsoft/BotFramework-WebChat/pull/5460), PR [#5469](https://github.com/microsoft/BotFramework-WebChat/pull/5469), PR [5470](https://github.com/microsoft/BotFramework-WebChat/pull/5470), PR [#5501](https://github.com/microsoft/BotFramework-WebChat/pull/5501) by [@lexi-taylor](https://github.com/lexi-taylor), and [@OEvgeny](https://github.com/OEvgeny)
102102
- <kbd>ESCAPE</kbd> key should reset the feedback form, in PR [#5480](https://github.com/microsoft/BotFramework-WebChat/pull/5480), by [@compulim](https://github.com/compulim), in PR [#5493](https://github.com/microsoft/BotFramework-WebChat/pull/5493) by [@lexi-taylor](https://github.com/lexi-taylor)
103103
- Added multi-dimensional grouping, `styleOptions.groupActivitiesBy`, and `useGroupActivitiesByName` hook, in PR [#5471](https://github.com/microsoft/BotFramework-WebChat/pull/5471), by [@compulim](https://github.com/compulim)
104104
- Existing behavior will be kept and activities will be grouped by `sender` followed by `status`
@@ -299,6 +299,7 @@ Notes: web developers are advised to use [`~` (tilde range)](https://github.com/
299299
- Updated file-based import with `.js` extension and removed the file extension from build config, by [@compulim](https://github.com/compulim), in PR [#5516](https://github.com/microsoft/BotFramework-WebChat/pull/5516)
300300
- Fixed [#5518](https://github.com/microsoft/BotFramework-WebChat/issues/5518). Minimal bundled build should work properly, in PR [#5507](https://github.com/microsoft/BotFramework-WebChat/pull/5507), by [@compulim](https://github.com/compulim)
301301
- Fixed [#5520](https://github.com/microsoft/BotFramework-WebChat/issues/5520). Version information should be injected when installed via npm, in PR [#5521](https://github.com/microsoft/BotFramework-WebChat/pull/5521), by [@compulim](https://github.com/compulim)
302+
- Fixed aria-label only announcing placeholder in feedback form, in PR [#5567](https://github.com/microsoft/BotFramework-WebChat/pull/5567)
302303
- Fixed placing focus on the code block content, so it is possible to scroll code via keyboard, in PR [#5575](https://github.com/microsoft/BotFramework-WebChat/pull/5575), by [@OEvgeny](https://github.com/OEvgeny)
303304

304305
### Removed

__tests__/html2/feedbackForm/feedback.form.activity.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@
8181
1000
8282
);
8383

84+
// Validate aria labelledby is present for feedback form and matching elements are present
85+
const feedbackFormSendBox = pageElements.byTestId('feedback sendbox');
86+
const ariaLabelledBy = feedbackFormSendBox.getAttribute('aria-labelledby');
87+
expect(ariaLabelledBy).toContain('feedback-form__form-header__id');
88+
const ariaDescribedBy = feedbackFormSendBox.getAttribute('aria-describedby');
89+
expect(ariaDescribedBy).toContain('feedback-form__form-footer__id');
90+
await pageObjects.verifyDOMIntegrity();
91+
8492
// WHEN: The cancel button is clicked.
8593
await host.sendTab(2);
8694
await host.sendKeys('ENTER');
4 Bytes
Loading
-40 Bytes
Loading
165 Bytes
Loading

packages/component/src/ActivityFeedback/private/FeedbackForm.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { hooks } from 'botframework-webchat-api';
22
import { useStyles } from '@msinternal/botframework-webchat-styles/react';
33
import React, { memo, useCallback, useEffect, useRef, useState, type FormEventHandler } from 'react';
4-
4+
import useUniqueId from '../../hooks/internal/useUniqueId';
55
import Markdownable from '../../Attachment/Text/private/Markdownable';
66
import testIds from '../../testIds';
77
import { TextArea } from '../../TextArea';
@@ -15,6 +15,8 @@ const { useLocalizer } = hooks;
1515
function FeedbackForm() {
1616
const classNames = useStyles(styles);
1717
const { useFeedbackText, useSelectedAction } = useActivityFeedbackHooks();
18+
const feedbackFormHeaderId = useUniqueId('feedback-form__form-header__id');
19+
const disclaimerId = useUniqueId('feedback-form__form-footer__id');
1820

1921
const [selectedAction] = useSelectedAction();
2022
const [hasFocus, setHasFocus] = useState(false);
@@ -42,9 +44,18 @@ function FeedbackForm() {
4244

4345
return (
4446
<div className={classNames['feedback-form__form']}>
45-
<span className={classNames['feedback-form__form-header']}>{localize('FEEDBACK_FORM_TITLE')}</span>
47+
<span
48+
className={classNames['feedback-form__form-header']}
49+
// "id" is required for "aria-labelledby"
50+
// eslint-disable-next-line react/forbid-dom-props
51+
id={feedbackFormHeaderId}
52+
>
53+
{localize('FEEDBACK_FORM_TITLE')}
54+
</span>
4655
<div className={classNames['feedback-form__text-box']}>
4756
<TextArea
57+
aria-describedby={disclaimer ? disclaimerId : undefined}
58+
aria-labelledby={feedbackFormHeaderId}
4859
className={classNames['feedback-form__text-area']}
4960
data-testid={testIds.feedbackSendBox}
5061
onInput={handleMessageChange}
@@ -54,7 +65,9 @@ function FeedbackForm() {
5465
value={userFeedback}
5566
/>
5667
</div>
57-
{disclaimer && <Markdownable className={classNames['feedback-form__form-footer']} text={disclaimer} />}
68+
{disclaimer && (
69+
<Markdownable className={classNames['feedback-form__form-footer']} id={disclaimerId} text={disclaimer} />
70+
)}
5871
<div className={classNames['feedback-form__submission-button-bar']}>
5972
<button className={classNames['feedback-form__submit-button']} type="submit">
6073
{localize('FEEDBACK_FORM_SUBMIT_BUTTON_LABEL')}

packages/component/src/Attachment/Text/private/Markdownable.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ import { useRenderMarkdownAsHTML } from '../../../hooks';
66
const markdownablePropsSchema = pipe(
77
object({
88
className: optional(string()),
9+
id: optional(string()),
910
text: string()
1011
}),
1112
readonly()
1213
);
1314

1415
type MarkdownableProps = InferInput<typeof markdownablePropsSchema>;
1516

16-
function Markdownable({ className, text }: MarkdownableProps) {
17+
function Markdownable({ className, id, text }: MarkdownableProps) {
1718
const renderMarkdownAsHTML = useRenderMarkdownAsHTML('message activity');
1819

1920
const innerHTML = useMemo<Readonly<{ __html: string }> | undefined>(
@@ -22,10 +23,15 @@ function Markdownable({ className, text }: MarkdownableProps) {
2223
);
2324

2425
return innerHTML ? (
25-
// eslint-disable-next-line react/no-danger
26-
<span className={className} dangerouslySetInnerHTML={innerHTML} />
26+
// "id" is required for "aria-labelledby"
27+
// eslint-disable-next-line react/forbid-dom-props, react/no-danger
28+
<span className={className} dangerouslySetInnerHTML={innerHTML} id={id} />
2729
) : (
28-
<span className={className}>{text}</span>
30+
// "id" is required for "aria-labelledby"
31+
// eslint-disable-next-line react/forbid-dom-props
32+
<span className={className} id={id}>
33+
{text}
34+
</span>
2935
);
3036
}
3137

packages/component/src/TextArea/TextArea.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ const { useUIState } = hooks;
1818
const TextArea = forwardRef<
1919
HTMLTextAreaElement,
2020
Readonly<{
21-
'aria-label'?: string | undefined;
21+
'aria-describedby'?: string | undefined;
22+
'aria-labelledby'?: string | undefined;
2223
className?: string | undefined;
2324
completion?: ReactNode | undefined;
2425
'data-testid'?: string | undefined;
@@ -80,11 +81,13 @@ const TextArea = forwardRef<
8081
) : (
8182
<Fragment>
8283
<div className={cx(classNames['text-area-doppelganger'], classNames['text-area-shared'])}>
83-
{props.completion ? props.completion : props.value || props.placeholder}{' '}
84+
{props.completion ? props.completion : props.value}{' '}
8485
</div>
8586
<textarea
87+
aria-describedby={props['aria-describedby']}
8688
aria-disabled={disabled}
87-
aria-label={props['aria-label']}
89+
aria-labelledby={props['aria-labelledby']}
90+
aria-placeholder={props.placeholder}
8891
className={cx(classNames['text-area-input'], classNames['text-area-shared'])}
8992
data-testid={props['data-testid']}
9093
onCompositionEnd={handleCompositionEnd}

0 commit comments

Comments
 (0)