Skip to content

Commit 65042b5

Browse files
authored
feat(feedback): Trigger button aria label configuration (#13008)
Adds `triggerAriaLabel` to configure the aria label of the trigger button. The aria label is set to the first value that's non-empty: 1. `triggerAriaLabel` 2. `triggerLabel` 3. TRIGGER_LABEL ("Report a Bug") Closes #12505
1 parent edea287 commit 65042b5

File tree

4 files changed

+77
-4
lines changed

4 files changed

+77
-4
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { TRIGGER_LABEL } from '../../constants';
2+
import { getFeedback } from '../getFeedback';
3+
import { buildFeedbackIntegration } from '../integration';
4+
import { mockSdk } from '../mockSdk';
5+
6+
describe('Actor', () => {
7+
it('renders the actor button', () => {
8+
const feedbackIntegration = buildFeedbackIntegration({
9+
lazyLoadIntegration: jest.fn(),
10+
});
11+
12+
const configuredIntegration = feedbackIntegration({});
13+
mockSdk({
14+
sentryOptions: {
15+
integrations: [configuredIntegration],
16+
},
17+
});
18+
19+
const feedback = getFeedback();
20+
expect(feedback).toBeDefined();
21+
22+
const actorComponent = feedback!.createWidget();
23+
24+
expect(actorComponent.el).toBeInstanceOf(HTMLButtonElement);
25+
expect(actorComponent.el?.textContent).toBe(TRIGGER_LABEL);
26+
});
27+
28+
it('renders the correct aria label for the button', () => {
29+
const feedbackIntegration = buildFeedbackIntegration({
30+
lazyLoadIntegration: jest.fn(),
31+
});
32+
33+
const configuredIntegration = feedbackIntegration({});
34+
mockSdk({
35+
sentryOptions: {
36+
integrations: [configuredIntegration],
37+
},
38+
});
39+
40+
const feedback = getFeedback();
41+
expect(feedback).toBeDefined();
42+
43+
// aria label is the same as trigger label when the trigger label isn't empty
44+
const actorDefault = feedback!.createWidget({ triggerLabel: 'Button' });
45+
46+
expect(actorDefault.el?.textContent).toBe('Button');
47+
expect(actorDefault.el?.ariaLabel).toBe('Button');
48+
49+
// aria label is default text when trigger label is empty and aria isn't configured
50+
const actorIcon = feedback!.createWidget({ triggerLabel: '' });
51+
52+
expect(actorIcon.el?.textContent).toBe('');
53+
expect(actorIcon.el?.ariaLabel).toBe(TRIGGER_LABEL);
54+
55+
// aria label is the triggerAriaLabel if it's configured
56+
const actorAria = feedback!.createWidget({ triggerLabel: 'Button', triggerAriaLabel: 'Aria' });
57+
58+
expect(actorAria.el?.textContent).toBe('Button');
59+
expect(actorAria.el?.ariaLabel).toBe('Aria');
60+
});
61+
});

packages/feedback/src/core/components/Actor.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { DOCUMENT } from '../../constants';
1+
import { DOCUMENT, TRIGGER_LABEL } from '../../constants';
22
import { createActorStyles } from './Actor.css';
33
import { FeedbackIcon } from './FeedbackIcon';
44

55
export interface ActorProps {
66
triggerLabel: string;
7+
triggerAriaLabel: string;
78
shadow: ShadowRoot;
89
}
910

@@ -22,12 +23,12 @@ export interface ActorComponent {
2223
/**
2324
* The sentry-provided button to open the feedback modal
2425
*/
25-
export function Actor({ triggerLabel, shadow }: ActorProps): ActorComponent {
26+
export function Actor({ triggerLabel, triggerAriaLabel, shadow }: ActorProps): ActorComponent {
2627
const el = DOCUMENT.createElement('button');
2728
el.type = 'button';
2829
el.className = 'widget__actor';
2930
el.ariaHidden = 'false';
30-
el.ariaLabel = triggerLabel;
31+
el.ariaLabel = triggerAriaLabel || triggerLabel || TRIGGER_LABEL;
3132
el.appendChild(FeedbackIcon());
3233
if (triggerLabel) {
3334
const label = DOCUMENT.createElement('span');

packages/feedback/src/core/integration.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ export const buildFeedbackIntegration = ({
9999
submitButtonLabel = SUBMIT_BUTTON_LABEL,
100100
successMessageText = SUCCESS_MESSAGE_TEXT,
101101
triggerLabel = TRIGGER_LABEL,
102+
triggerAriaLabel = '',
102103

103104
// FeedbackCallbacks
104105
onFormOpen,
@@ -124,6 +125,7 @@ export const buildFeedbackIntegration = ({
124125
themeLight,
125126

126127
triggerLabel,
128+
triggerAriaLabel,
127129
cancelButtonLabel,
128130
submitButtonLabel,
129131
confirmButtonLabel,
@@ -258,7 +260,11 @@ export const buildFeedbackIntegration = ({
258260
const _createActor = (optionOverrides: OverrideFeedbackConfiguration = {}): ActorComponent => {
259261
const mergedOptions = mergeOptions(_options, optionOverrides);
260262
const shadow = _createShadow(mergedOptions);
261-
const actor = Actor({ triggerLabel: mergedOptions.triggerLabel, shadow });
263+
const actor = Actor({
264+
triggerLabel: mergedOptions.triggerLabel,
265+
triggerAriaLabel: mergedOptions.triggerAriaLabel,
266+
shadow,
267+
});
262268
_attachTo(actor.el, {
263269
...mergedOptions,
264270
onFormOpen() {

packages/types/src/feedback/config.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ export interface FeedbackTextConfiguration {
9292
*/
9393
triggerLabel: string;
9494

95+
/**
96+
* The aria label for the Feedback widget button that opens the dialog
97+
*/
98+
triggerAriaLabel: string;
99+
95100
/**
96101
* The label for the Feedback form cancel button that closes dialog
97102
*/

0 commit comments

Comments
 (0)