Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Appropriate DOM structures for tabs widgets #2310

Open
zelliott opened this issue May 4, 2022 · 3 comments
Open

Appropriate DOM structures for tabs widgets #2310

zelliott opened this issue May 4, 2022 · 3 comments

Comments

@zelliott
Copy link

zelliott commented May 4, 2022

Most tab widgets seem to have the following DOM structure (note that throughout these examples some important DOM attributes are omitted for brevity):

<div role="tablist">
  <div role="tab" aria-selected="true" aria-controls="first">First</div>
  <div role="tab" aria-selected="false" aria-controls="second">Second</div>
</div>
<div role="tabpanel" id="first">First panel</div>
<div role="tabpanel" id="second" class="is-hidden">Second panel</div>

Note that the first tab is selected, and thus the second panel is hidden from the page with the .is-hidden class (which applies something like display: none to the element).

In my case, it's difficult to render multiple tabpanel elements. Instead, the content within the single tabpanel element dynamically updates based upon the selected tab. Thus, I'm wondering if there are any accessibility concerns with either of the following two alternative DOM structures:

Alternative 1

  • Only add aria-controls to the active tab (JavaScript toggles the attribute on tab selection).
  • Only render one tabpanel element with a static id (e.g. my-panel) and have aria-controls always point to that id.

When first tab is selected:

<div role="tablist">
  <div role="tab" aria-selected="true" aria-controls="my-panel">First</div>
  <div role="tab" aria-selected="false">Second</div>
</div>
<div role="tabpanel" id="my-panel">First panel</div>

When second tab is selected:

<div role="tablist">
  <div role="tab" aria-selected="false">First</div>
  <div role="tab" aria-selected="true" aria-controls="my-panel">Second</div>
</div>
<div role="tabpanel" id="my-panel">Second panel</div>

Alternative 2

  • Add aria-controls to both tabs, but have them both point to the same tabpanel.
  • Again only render one tabpanel element with a static id.
  • When the selected tab changes, the tabpanel contents dynamically change.

When first tab is selected:

<div role="tablist">
  <div role="tab" aria-selected="true" aria-controls="my-panel">First</div>
  <div role="tab" aria-selected="false" aria-controls="my-panel">Second</div>
</div>
<div role="tabpanel" id="my-panel">First panel</div>

When second tab is selected:

<div role="tablist">
  <div role="tab" aria-selected="false" aria-controls="my-panel">First</div>
  <div role="tab" aria-selected="true" aria-controls="my-panel">Second</div>
</div>
<div role="tabpanel" id="my-panel">Second panel</div>

Alternative 2 is what I have today, but it was brought to my attention that it could be confusing for an unselected tab's aria-controls to point to the active tabpanel. This seemed like a valid concern, but at the same time, in the canonical examples of tab widgets, the unselected tab's aria-controls points to nothing altogether (as it points to a tabpanel that's hidden with .is-hidden and thus not accessible to SRs). Changing from alternative 2 to alternative 1 seemed like it would address this concern, but I wasn't sure if it would be problematic from a SR point-of-view to be dynamically adding/removing aria-controls attributes. Any thoughts would be greatly appreciated - thanks!

@zelliott zelliott changed the title Use of aria-controls on unselected tabs Appropriate DOM structure for tabs widgets May 4, 2022
@zelliott zelliott changed the title Appropriate DOM structure for tabs widgets Appropriate DOM structures for tabs widgets May 4, 2022
@JAWS-test
Copy link

I think it is a bug that aria-controls points to a container that is not visible (display:none). I would use aria-controls only on the active tab. Besides, aria-controls has little relevance (see w3c/aria#995).

@zelliott
Copy link
Author

zelliott commented May 5, 2022

So then you would consider Alternative 1 to be the "most correct" out of the structures above?

I think it is a bug that aria-controls points to a container that is not visible (display:none).

If the other APG maintainers agree, then we should update the tabs example accordingly.

@JAWS-test
Copy link

If there would be a screen reader support of aria-controls, the first variant is much better. With the second one I would refer from the not active tab to the wrong tabpanel.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants