如何在React Web应用程序中实现对影子根内内容的HTML可访问性?

huangapple go评论72阅读模式
英文:

How to achieve HTML accessibility for content inside shadow-root in a React web app?

问题

我有一个主要的React Web应用程序,它从另一个应用程序获取内容并将其注入。被注入组件的内容完全位于一个影子根内。简而言之,它看起来像这样:

<主应用程序>
...内容
   <web组件>
   #shadow-root(open)
      <div>
      ...内容
      </div>
   </web组件>
</主应用程序>

我需要使从注入组件中获取的内容可以从主应用程序访问。ARIA属性不起作用。编写自定义HTMLElements也不是一个选项,因为我必须遵守一些严格的规则。主应用程序和注入组件都是使用React编写的。有没有一种常见的方法可以使影子根内部的内容可访问?

我尝试在我注入的组件中添加子元素,但显然它在影子根外部起作用,在内部则不起作用。
我还尝试在影子根外部放置<label hidden id="testId"></label>,并通过ariaLabeledBy将其连接到所需的元素,但也没有起作用。

我要注入的Web组件代码如下:

import { Button } from "@mui/material";
import ReactDOM from "react-dom";

export class WebComponent extends HTMLElement {
    connectedCallback() {
        const appContainer = document.createElement("div");
        const mountPoint = document.createElement("div");
        mountPoint.appendChild(appContainer);
        this.attachShadow({ mode: "open" }).appendChild(mountPoint);

        ReactDOM.render(
            <MainApp/>, appContainer
        )
    }
}

const MainApp = () => {
    // Aria-labels will be skipped by screen readers.
    // Text content also will be skipped by screen readers.
    return (
        <Button aria-label="TEST">TestBtn</Button>
    )
}

customElements.define("web-component", WebComponent);

该组件通过在我的主Web应用程序中调用connectedCallback()方法进行呈现。不幸的是,我无法粘贴实际的代码,但我希望这可以展示问题的上下文。

英文:

I have one main react webapp which takes content from another and has it injected. The content of an injected component is whole inside a shadow-root. In short it looks like:

&lt;main-app&gt;
...content
   &lt;web-component&gt;
   #shadow-root(open)
      &lt;div&gt;
      ...content
      &lt;/div&gt;
   &lt;/web-component&gt;
&lt;/main-app&gt;

I gotta make content from injected component accessible from the main app. Aria attributes don't work. Writing custom HTMLElements is also not an option, as I gotta stick to some strict rules. Both - main app and injected component are written in react. Is there a common way, to make content inside shadow-root accessible?

I've tried appending children in the component I'm injecting, but obviously it worked outisde shadow-root and inside it did not.
I have also tried putting <label hidden id="testId"></label> outsie shadow-root and connecting it with desired element via ariaLabeledBy, but it also did not work.

The web component code that I'm injecting looks like:

import { Button } from &quot;@mui/material&quot;;
import ReactDOM from &quot;react-dom&quot;;

export class WebComponent extends HTMLElement {
    connectedCallback() {
        const appContainer = document.createElement(&quot;div&quot;);
        const mountPoint = document.createElement(&quot;div&quot;);
        mountPoint.appendChild(appContainer);
        this.attachShadow({ mode: &quot;open&quot; }).appendChild(mountPoint);

        ReactDOM.render(
            &lt;MainApp/&gt;, appContainer
        )
    }
}

const MainApp = () =&gt; {
    // Aria-labels will be skipped by screen readers.
    // Text content also will be skipped by screen readers.
    return (
        &lt;Button aria-label=&quot;TEST&quot;&gt;TestBtn&lt;/Button&gt;
    )
}

customElements.define(&quot;web-component&quot;, WebComponent);

The component is being rendered by calling connectedCallback() method in my main web app. Unfortunately, it's not possible for me to paste the actual code, but I hope it can show the context of the problem.

答案1

得分: 0

我成功找到了一个解决方案。

对于浏览器内置的内容阅读器,唯一有效的解决方案是使用挂钩动态添加标签元素,位于阴影根内容之外。这些元素不可见,但读者可以朗读内容。

对于像NVDA按钮、输入框等屏幕阅读器,无需任何变通方法即可正常工作。唯一的问题是,像标题和段落这样的文本内容在页面加载时不会立即朗读。这并不是一个错误,也与阴影根无关,但在我的情况下,我希望页面加载后立即朗读。在我的特定情况下,添加了role="alert"属性就解决了这个问题。

希望有人会发现这对他们有用。

英文:

I've managed to find a solution.

For the browser's built-in content reader, the only working solution was to dynamically add label elements just outside shadow-root content using hooks. It was not visible, but readers were available to read the content aloud.

For screen readers like NVDA buttons, inputs etc worked without any workaround. The only problem was that text content like headers and paragraphs was not read immediately when the page loaded. It wasn't a bug, nor it was related to shadow-root, but in my case, I needed it to be read right after the page loaded. Adding the role="alert" attribute solved it in my specific case.

Hope, that someone finds it useful.

huangapple
  • 本文由 发表于 2023年6月1日 22:07:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/76382790.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定