Skip to content

Commit 373d633

Browse files
authored
♿ [Story a11y] Improve screen reader output for interactive components (#32969)
* Interactive components options to buttons * Changed comment * Added aria live * Ussing classList to get option * Added readability to quizzes * Changing polls * Fixing binary polls and polls * Fix double reading of option in quiz * Consistency in string interpolation * Remove unused import
1 parent 4b8c9bf commit 373d633

File tree

5 files changed

+59
-27
lines changed

5 files changed

+59
-27
lines changed

extensions/amp-story-interactive/0.1/amp-story-interactive-abstract.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,7 @@ export class AmpStoryInteractive extends AMP.BaseElement {
542542
* @protected @abstract
543543
* @param {!Array<!InteractiveOptionType>} unusedOptionsData
544544
*/
545-
updateOptionPercentages_(unusedOptionsData) {
545+
displayOptionsData(unusedOptionsData) {
546546
// Subclass must implement
547547
}
548548

@@ -792,7 +792,7 @@ export class AmpStoryInteractive extends AMP.BaseElement {
792792

793793
if (this.optionsData_) {
794794
this.rootEl_.classList.add('i-amphtml-story-interactive-has-data');
795-
this.updateOptionPercentages_(this.optionsData_);
795+
this.displayOptionsData(this.optionsData_);
796796
}
797797
this.getOptionElements().forEach((el) => {
798798
el.setAttribute('tabindex', -1);

extensions/amp-story-interactive/0.1/amp-story-interactive-binary-poll.js

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ const buildOptionTemplate = (element) => {
7171
<span class="i-amphtml-story-interactive-option-title"
7272
><span class="i-amphtml-story-interactive-option-title-text"></span
7373
></span>
74-
<span class="i-amphtml-story-interactive-option-percentage-text"
74+
<span
75+
class="i-amphtml-story-interactive-option-percentage-text"
76+
aria-hidden="true"
7577
>0%</span
7678
>
7779
</span>
@@ -220,29 +222,29 @@ export class AmpStoryInteractiveBinaryPoll extends AmpStoryInteractive {
220222
/**
221223
* @override
222224
*/
223-
updateOptionPercentages_(responseData) {
225+
displayOptionsData(responseData) {
224226
if (!responseData) {
225227
return;
226228
}
227229

228230
const percentages = this.preprocessPercentages_(responseData);
229231

230-
percentages.forEach((percentage, index) => {
232+
this.getOptionElements().forEach((el, index) => {
231233
// TODO(jackbsteinberg): Add i18n support for various ways of displaying percentages.
232-
const currOption = this.getOptionElements()[index];
233-
currOption.querySelector(
234+
const percentage = percentages[index];
235+
const percentageEl = el.querySelector(
234236
'.i-amphtml-story-interactive-option-percentage-text'
235-
).textContent = `${percentage}%`;
237+
);
238+
percentageEl.textContent = `${percentage}%`;
239+
percentageEl.removeAttribute('aria-hidden');
236240

237241
setStyle(
238-
currOption.querySelector(
239-
'.i-amphtml-story-interactive-option-percent-bar'
240-
),
242+
el.querySelector('.i-amphtml-story-interactive-option-percent-bar'),
241243
'transform',
242244
`scaleX(${percentage * 0.01 * 2})`
243245
);
244246

245-
const textContainer = currOption.querySelector(
247+
const textContainer = el.querySelector(
246248
'.i-amphtml-story-interactive-option-text-container'
247249
);
248250

@@ -252,6 +254,12 @@ export class AmpStoryInteractiveBinaryPoll extends AmpStoryInteractive {
252254
this.getTransformVal_(percentage) * (index === 0 ? 1 : -1)
253255
}%) !important`
254256
);
257+
if (responseData[index].selected) {
258+
textContainer.setAttribute(
259+
'aria-label',
260+
'selected ' + textContainer.textContent
261+
);
262+
}
255263

256264
if (percentage === 0) {
257265
setStyle(textContainer, 'opacity', '0');

extensions/amp-story-interactive/0.1/amp-story-interactive-poll.js

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,19 +128,24 @@ export class AmpStoryInteractivePoll extends AmpStoryInteractive {
128128
/**
129129
* @override
130130
*/
131-
updateOptionPercentages_(optionsData) {
131+
displayOptionsData(optionsData) {
132132
if (!optionsData) {
133133
return;
134134
}
135135

136136
const percentages = this.preprocessPercentages_(optionsData);
137137

138-
percentages.forEach((percentage, index) => {
139-
const currOption = this.getOptionElements()[index];
140-
currOption.querySelector(
138+
this.getOptionElements().forEach((el, index) => {
139+
if (optionsData[index].selected) {
140+
const textEl = el.querySelector(
141+
'.i-amphtml-story-interactive-option-text'
142+
);
143+
textEl.setAttribute('aria-label', 'selected ' + textEl.textContent);
144+
}
145+
el.querySelector(
141146
'.i-amphtml-story-interactive-option-percentage-text'
142-
).textContent = `${percentage}`;
143-
setStyle(currOption, '--option-percentage', percentages[index] + '%');
147+
).textContent = percentages[index];
148+
setStyle(el, '--option-percentage', percentages[index] + '%');
144149
});
145150
}
146151

extensions/amp-story-interactive/0.1/amp-story-interactive-quiz.js

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {CSS} from '../../../build/amp-story-interactive-quiz-0.1.css';
2222
import {LocalizedStringId} from '../../../src/localized-strings';
2323
import {htmlFor} from '../../../src/static-template';
2424
import {setStyle} from '../../../src/style';
25+
import objstr from 'obj-str';
2526

2627
/**
2728
* Generates the template for the quiz.
@@ -121,9 +122,10 @@ export class AmpStoryInteractiveQuiz extends AmpStoryInteractive {
121122
const convertedOption = buildOptionTemplate(this.element);
122123

123124
// Fill in the answer choice and set the option ID
124-
convertedOption.querySelector(
125+
const answerChoiceEl = convertedOption.querySelector(
125126
'.i-amphtml-story-interactive-quiz-answer-choice'
126-
).textContent = this.localizedAnswerChoices_[index];
127+
);
128+
answerChoiceEl.textContent = this.localizedAnswerChoices_[index];
127129
convertedOption.optionIndex_ = option['optionIndex'];
128130

129131
// Extract and structure the option information
@@ -148,18 +150,35 @@ export class AmpStoryInteractiveQuiz extends AmpStoryInteractive {
148150
/**
149151
* @override
150152
*/
151-
updateOptionPercentages_(optionsData) {
153+
displayOptionsData(optionsData) {
152154
if (!optionsData) {
153155
return;
154156
}
155157

156158
const percentages = this.preprocessPercentages_(optionsData);
157-
percentages.forEach((percentage, index) => {
158-
const option = this.getOptionElements()[index];
159-
option.querySelector(
159+
160+
this.getOptionElements().forEach((el, index) => {
161+
// Update the aria-label so they read "selected" and "correct" or "incorrect"
162+
const ariaDescription = objstr({
163+
selected: optionsData[index].selected,
164+
correct: el.hasAttribute('correct'),
165+
incorrect: !el.hasAttribute('correct'),
166+
});
167+
el.querySelector(
168+
'.i-amphtml-story-interactive-quiz-answer-choice'
169+
).setAttribute('aria-hidden', true);
170+
const optionText = el.querySelector(
171+
'.i-amphtml-story-interactive-quiz-option-text'
172+
);
173+
optionText.setAttribute(
174+
'aria-label',
175+
ariaDescription + ' ' + optionText.textContent
176+
);
177+
// Update percentage text
178+
el.querySelector(
160179
'.i-amphtml-story-interactive-quiz-percentage-text'
161-
).textContent = `${percentage}%`;
162-
setStyle(option, '--option-percentage', percentage + '%');
180+
).textContent = `${percentages[index]}%`;
181+
setStyle(el, '--option-percentage', `${percentages[index]}%`);
163182
});
164183
}
165184
}

extensions/amp-story-interactive/0.1/amp-story-interactive-results.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ export class AmpStoryInteractiveResults extends AmpStoryInteractive {
268268
}
269269

270270
/** @override */
271-
updateOptionPercentages_(unusedOptionsData) {
271+
displayOptionsData(unusedOptionsData) {
272272
// TODO(mszylkowski): Show percentages of categories if endpoint.
273273
}
274274

0 commit comments

Comments
 (0)