Dunfey · Hotel WWDC as data, est. 1983
Front desk everything
Years
Topics

2022 EssentialsSafari & WebSwiftUI & UI FrameworksAccessibility & Inclusion

WWDC22 · 15 min · Essentials / Safari & Web / SwiftUI & UI Frameworks / Accessibility & Inclusion

What’s new in web accessibility

Discover techniques for building rich, accessible web apps with custom controls, SSML, and the dialog element. We’ll discuss different assistive technologies and help you learn how to use them when testing the accessibility of your web apps.

Watch at developer.apple.com ↗

Transcript all transcripts

Code shown on screen · 11 snippets

PizzaControl class with click event listener javascript · at 3:06 ↗
class PizzaControl {
  constructor(id) {
    this.control = document.getElementById(id);
    this.sliceCount = 4;
    
    this.control.addEventListener("click", (event) => {
      const newSliceCount = this.computeSliceCount(event);
      this.update(newSliceCount);
    });
  }
}
PizzaControl HTML markup markdown · at 4:23 ↗
<div id="pizza-input" 
     role="slider" tabindex="0"
     aria-valuemin="0" aria-valuemax="8"
     aria-valuenow="4" aria-valuetext="4 slices">
</div>
PizzaControl class with keydown event listener javascript · at 5:15 ↗
class PizzaControl {
  constructor(id) {
    this.control = document.getElementById(id);
    this.sliceCount = 4;

    // …click event listener…
    
    this.control.addEventListener("keydown", (event) => {
      const key = event.key;
      if (key === "ArrowRight" || key === "ArrowUp")
        this.update(this.sliceCount + 1);
      else if (key === "ArrowLeft" || key === "ArrowDown")
        this.update(this.sliceCount - 1);
    });
  }
}
PizzaControl class update function javascript · at 5:41 ↗
class PizzaControl {
  // …constructor…
  
  update(newSliceCount) {
    this.sliceCount = Math.max(0, Math.min(newSliceCount, 8));

    // Visually re-render `this.sliceCount` slices
    // …

    // Update the ARIA representation of the control
    this.control.setAttribute("aria-valuenow", this.sliceCount);
    const sliceModifier = this.sliceCount === 1 ? "slice" : "slices";
    this.control.setAttribute("aria-valuetext", `${this.sliceCount} ${sliceModifier}`);
  }
}
SSML examples markdown · at 7:52 ↗
<speak>
  Breathe in <break time="3s"/> and breathe out.
</speak>

<speak>
  <phoneme alphabet="ipa" ph="təˈmeɪtoʊ">tomato</phoneme>
  <phoneme alphabet="ipa" ph="təˈmɑːtəʊ">tomato</phoneme>
</speak>

<speak>
  <prosody pitch="-2st" rate="slow" volume="loud">
    Hello world!
  </prosody>
</speak>
"Read question" button HTML markup markdown · at 8:45 ↗
<button id="read-question-btn">
  Read question<span aria-hidden="true">🔊</span>
</button>
wrapWithSSML JavaScript function javascript · at 8:57 ↗
function wrapWithSSML(phrase, locale) {
  return `
    <break time=“100ms"/>
    <prosody rate=“80%">
      <lang xml:lang="${locale}">
        ${phrase}
      </lang>
    </prosody>
  `;
}
Read question button click event listener javascript · at 9:24 ↗
const readQuestionButton =
  document.getElementById("read-question-btn");

readQuestionButton.addEventListener("click", () => {
  const ssml = `
    <speak>
      How do you say
        ${wrapWithSSML("the water", "en-US")}
      in Spanish?
      ${wrapWithSSML("El agua", "es-MX")}
      ${wrapWithSSML("La abuela", "es-MX")}
      ${wrapWithSSML("La abeja", "es-MX")}
      ${wrapWithSSML("El árbol", "es-MX")}
    </speak>
  `;
  const utterance = new SpeechSynthesisUtterance(ssml);
  window.speechSynthesis.speak(utterance);
});
Show score dialog HTML markup markdown · at 11:33 ↗
<dialog id="show-score-modal">
  <form method="dialog">
    You got all six questions correct. Great work!
    <button type="submit">Close</button>
  </form>
</dialog>
JavaScript to open show score dialog javascript · at 11:51 ↗
const showScoreButton =
  document.getElementById("show-score-btn");

showScoreButton.addEventListener("click", () => {
  document
    .getElementById("show-score-modal")
    .showModal();
});
Show score dialog with autofocus and aria-labelledby attribute markdown · at 13:23 ↗
<dialog id="show-score-modal" aria-labelledby="modal-content">
  <form method="dialog">
    <span id="modal-content">
      You got all six questions correct. Great work!
    </span>
    <button type="submit" autofocus>Close</button>
  </form>
</dialog>

Resources