คอมโพเนนต์เว็บที่เข้าถึงได้

ขอบเขต Shadow จะเปลี่ยนวิธีการทำงานของความหมายและ ARIA ความล้มเหลว 2 อย่างที่พบมากที่สุดคือความหมายที่ขาดหายไปภายใน Shadow Tree และการอ้างอิง ARIA ที่ใช้งานไม่ได้โดยไม่มีการแจ้งเตือนเนื่องจากไม่สามารถข้าม Shadow Root ได้

เริ่มต้นจากมาร์กอัปที่สื่อความหมาย: ใช้ <button>, <nav>, <ul> จริงภายในเทมเพลตเพื่อให้ความหมายส่วนใหญ่มาโดยอัตโนมัติ และสำรอง ElementInternals/ARIA ไว้สำหรับส่วนที่ขาดหายไป

ความหมายเริ่มต้นผ่าน ElementInternals ARIA mixin

ตั้งค่าบทบาทและสถานะ ARIA ขององค์ประกอบที่กำหนดเองใน JS ผ่าน ElementInternals แทนการเขียนแอตทริบิวต์ ARIA ลงในโฮสต์ วิธีนี้จะคงความหมายเป็นค่าเริ่มต้นที่คอมโพเนนต์เป็นเจ้าของ ขณะเดียวกันก็ยังคงอนุญาตให้ผู้บริโภคแทนที่ความหมายเหล่านั้นด้วยแอตทริบิวต์ใน Light DOM

class ToggleSwitch extends HTMLElement {
  #internals;
  constructor() {
    super();
    this.#internals = this.attachInternals();
    this.#internals.role = 'switch';          // default role, no host attribute needed
    this.#internals.ariaChecked = 'false';    // exposed to the accessibility tree
    this.addEventListener('click', () => this.toggle());
    this.addEventListener('keydown', (e) => {
      if (e.key === ' ') { e.preventDefault(); this.toggle(); }
    });
  }
  connectedCallback() {
    // Put the host in the tab order on connect (setting tabIndex in the constructor throws on createElement).
    if (!this.hasAttribute('tabindex')) this.tabIndex = 0;
  }
  toggle() {
    const on = this.#internals.ariaChecked !== 'true';
    this.#internals.ariaChecked = String(on);
  }
}
customElements.define('toggle-switch', ToggleSwitch);

วิธีนี้จะช่วยหลีกเลี่ยงการสร้างความสับสนใน DOM ด้วยแอตทริบิวต์ ARIA และป้องกันไม่ให้ผู้ใช้ลบแอตทริบิวต์เหล่านั้นโดยไม่ตั้งใจ ขณะที่แผนผังการช่วยเหลือพิเศษยังคงเห็นบทบาทและสถานะที่ถูกต้อง

การจัดการโฟกัสและ delegatesFocus

  • เมื่อองค์ประกอบโฮสต์เป็นตัวควบคุมแบบอินเทอร์แอกทีฟและมีบทบาทและสถานะผ่าน ElementInternals (เช่น ToggleSwitch ด้านบน) ให้วางโฮสต์ในลำดับแท็บภายใน connectedCallback (if (!this.hasAttribute('tabindex')) this.tabIndex = 0 — ห้ามวางในคอนสตรัคเตอร์ ซึ่งจะแสดงข้อผิดพลาดใน document.createElement) เพื่อให้โฟกัสอยู่ที่โฮสต์และเทคโนโลยีความช่วยเหลือพิเศษจะประกาศบทบาทและสถานะของโฮสต์ อย่าตั้งค่า tabindex ในโฮสต์สำหรับคอมโพเนนต์แบบคงที่และไม่โต้ตอบ (เช่น ข้อความไฮไลต์หรือการ์ด)
  • แนบ Shadow Root ด้วย delegatesFocus: true เมื่อคอมโพเนนต์รวมการควบคุมที่โฟกัสได้ภายในซึ่งเป็นเจ้าของความหมาย (หรือในองค์ประกอบที่กำหนดเองที่เชื่อมโยงกับแบบฟอร์มด้วย static formAssociated = true) การโฟกัสโฮสต์ (และการคลิก <label> ที่เชื่อมโยงสำหรับองค์ประกอบที่เชื่อมโยงกับแบบฟอร์ม) จะส่งต่อโฟกัสไปยังองค์ประกอบย่อยที่โฟกัสได้รายการแรก และ :focus จะตรงกับโฮสต์ อย่ารวม delegatesFocus: true กับบทบาท/สถานะในโฮสต์ ไม่เช่นนั้นโฟกัสจะไปอยู่ที่องค์ประกอบด้านในและข้ามสถานะของโฮสต์ไป
  • สำหรับการย้ายโฟกัสหรือการย้ายโฟกัสไปยังส่วนที่เพิ่งแสดง ให้กำหนด tabindex="-1" ให้กับเป้าหมายและเรียกใช้ .focus() โดยกำหนดเป้าหมายที่โฟกัสได้โดยใช้โปรแกรมอย่างชัดเจนแทนที่จะอาศัยลำดับแท็บ

ความสัมพันธ์ของ ARIA ใน Shadow Root

  • บังคับ: id ที่อ้างอิงโดย aria-labelledby, aria-describedby, aria-controls ฯลฯ จะแก้ไขได้ภายในโครงสร้างของตัวเองขององค์ประกอบที่อ้างอิงเท่านั้น แอตทริบิวต์ที่อิงตาม id ใน Light DOM ไม่สามารถชี้ไปยัง id ภายใน Shadow Tree และในทางกลับกัน ระบบจะไม่สนใจการอ้างอิงโดยไม่มีการแจ้งเตือน
  • หากต้องการข้ามขอบเขต ให้ใช้พร็อพเพอร์ตี้ element ของ ARIA ที่แสดง (เช่น ariaLabelledByElements, ariaDescribedByElements เป็นต้น) ซึ่งใช้การอ้างอิงองค์ประกอบ JS โดยตรงแทนรหัส โดยจะแก้ไขภายนอก: องค์ประกอบภายใน Shadow Tree สามารถชี้ไปยังเป้าหมายใน Light DOM หรือโครงสร้างระดับบนสุด (รวมถึงเนื้อหาที่แบ่งช่อง) เพื่อให้คุณติดป้ายกำกับการควบคุมภายใน Shadow จากเนื้อหา Light DOM ได้ ซึ่งเป็นสิ่งที่การอ้างอิง id ไม่สามารถแสดงได้
  • แต่จะไม่แก้ไขเข้าด้านใน: องค์ประกอบจะอ้างอิงเข้าไปใน Shadow Tree ที่สืบทอดมาไม่ได้ (เช่น โฮสต์จะติดป้ายกำกับโดยเนื้อหา Shadow ของตัวเองไม่ได้) สำหรับทิศทางนั้น กลไก Reference Target ที่เกิดขึ้นใหม่เป็นทิศทางมาตรฐาน แต่ยังไม่มีให้บริการในวงกว้าง
  • เมื่อไม่สามารถแสดงความสัมพันธ์ได้ไม่ว่าด้วยวิธีใดก็ตาม ให้เก็บความสัมพันธ์นั้นไว้ภายในต้นไม้เดียว (แสดงผลป้ายกำกับในต้นไม้เดียวกัน) หรือใช้ข้อความ aria-label แทนการอ้างอิง id

กลยุทธ์สำรอง

ในกรณีที่ไม่มีมิกซ์อิน ElementInternals ARIA ให้ตั้งค่าบทบาทและสถานะ ARIA เป็นแอตทริบิวต์ในโฮสต์แทน (this.setAttribute('role', 'switch')) ซึ่งจะใช้ได้ทุกที่ โดยแลกกับการใส่แอตทริบิวต์ใน DOM ที่ผู้บริโภคสามารถลบล้างได้

ในกรณีที่พร็อพเพอร์ตี้องค์ประกอบ ARIA ที่แสดงผลไม่พร้อมใช้งาน ให้ใช้แอตทริบิวต์ aria-* ที่อิงตาม id สำหรับความสัมพันธ์ในโครงสร้างเดียวกัน ป้ายกำกับข้ามขอบเขตไม่มีรายการที่เทียบเท่าซึ่งอิงตาม id ดังนั้นให้กลับไปใช้ข้อความ aria-label