Skip to content

Commit 3aa8785

Browse files
committed
add aria label to feedback form send box
1 parent 88e4f00 commit 3aa8785

4 files changed

Lines changed: 27 additions & 6 deletions

File tree

__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+
expect(ariaLabelledBy).toContain('feedback-form__form-footer__id');
89+
expect(ariaLabelledBy).toContain('feedback-form__text-area__id');
90+
await pageObjects.verifyDOMIntegrity();
91+
8492
// WHEN: The cancel button is clicked.
8593
await host.sendTab(2);
8694
await host.sendKeys('ENTER');

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

Lines changed: 11 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,9 @@ 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');
20+
const textAreaId = useUniqueId('feedback-form__text-area__id');
1821

1922
const [selectedAction] = useSelectedAction();
2023
const [hasFocus, setHasFocus] = useState(false);
@@ -40,21 +43,26 @@ function FeedbackForm() {
4043
}
4144
}, [feedbackTextAreaRef, hasFocus, setHasFocus]);
4245

46+
const textAreaAriaLabelledBy = `${feedbackFormHeaderId} ${textAreaId}${disclaimer ? ` ${disclaimerId}` : ''}`;
47+
4348
return (
4449
<div className={classNames['feedback-form__form']}>
45-
<span className={classNames['feedback-form__form-header']}>{localize('FEEDBACK_FORM_TITLE')}</span>
50+
<span className={classNames['feedback-form__form-header']} id={feedbackFormHeaderId}>{localize('FEEDBACK_FORM_TITLE')}</span>
4651
<div className={classNames['feedback-form__text-box']}>
4752
<TextArea
53+
aria-label={localize('FEEDBACK_FORM_PLACEHOLDER')}
54+
aria-labelledby={textAreaAriaLabelledBy}
4855
className={classNames['feedback-form__text-area']}
4956
data-testid={testIds.feedbackSendBox}
57+
id={textAreaId}
5058
onInput={handleMessageChange}
5159
placeholder={localize('FEEDBACK_FORM_PLACEHOLDER')}
5260
ref={feedbackTextAreaRef}
5361
startRows={3}
5462
value={userFeedback}
5563
/>
5664
</div>
57-
{disclaimer && <Markdownable className={classNames['feedback-form__form-footer']} text={disclaimer} />}
65+
{disclaimer && <Markdownable id={disclaimerId} className={classNames['feedback-form__form-footer']} text={disclaimer} />}
5866
<div className={classNames['feedback-form__submission-button-bar']}>
5967
<button className={classNames['feedback-form__submit-button']} type="submit">
6068
{localize('FEEDBACK_FORM_SUBMIT_BUTTON_LABEL')}

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

Lines changed: 4 additions & 3 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, text, id }: MarkdownableProps) {
1718
const renderMarkdownAsHTML = useRenderMarkdownAsHTML('message activity');
1819

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

2425
return innerHTML ? (
2526
// eslint-disable-next-line react/no-danger
26-
<span className={className} dangerouslySetInnerHTML={innerHTML} />
27+
<span id={id} className={className} dangerouslySetInnerHTML={innerHTML} />
2728
) : (
28-
<span className={className}>{text}</span>
29+
<span id={id} className={className}>{text}</span>
2930
);
3031
}
3132

packages/component/src/TextArea/TextArea.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const TextArea = forwardRef<
1919
HTMLTextAreaElement,
2020
Readonly<{
2121
'aria-label'?: string | undefined;
22+
'aria-labelledby'?: string | undefined;
2223
className?: string | undefined;
2324
completion?: ReactNode | undefined;
2425
'data-testid'?: string | undefined;
@@ -32,6 +33,7 @@ const TextArea = forwardRef<
3233
* This ensures the flow of focus did not sent to document body
3334
*/
3435
hidden?: boolean | undefined;
36+
id?: string | undefined;
3537
onInput?: FormEventHandler<HTMLTextAreaElement> | undefined;
3638
placeholder?: string | undefined;
3739
startRows?: number | undefined;
@@ -85,8 +87,10 @@ const TextArea = forwardRef<
8587
<textarea
8688
aria-disabled={disabled}
8789
aria-label={props['aria-label']}
90+
aria-labelledby={props['aria-labelledby']}
8891
className={cx(classNames['text-area-input'], classNames['text-area-shared'])}
8992
data-testid={props['data-testid']}
93+
id={props['id']}
9094
onCompositionEnd={handleCompositionEnd}
9195
onCompositionStart={handleCompositionStart}
9296
onInput={props.onInput}

0 commit comments

Comments
 (0)