feat(curriculum): Add interactive examples to aria-expanded attribute lesson (#63554)

This commit is contained in:
shivanissingh
2025-11-06 16:34:04 +05:30
committed by GitHub
parent 4473258189
commit ea42bfc6e5

View File

@@ -5,7 +5,7 @@ challengeType: 19
dashedName: what-is-the-aria-expanded-attribute
---
# --description--
# --interactive--
The `aria-expanded` attribute is used for accessibility purposes to indicate if a control is expanded or collapsed. It's used in conjunction with collapsible widgets like menus, accordions and other disclosure widgets that control the visibility of content. The `aria-expanded` attribute is set to `true` if the control is expanded, or `false` if it is collapsed.
@@ -35,19 +35,78 @@ Additionally, the properties, `aria-controls` and `aria-owns` can be used in com
Let's start with `aria-controls`. When used with `aria-expanded`, the `aria-controls` attribute is used to specify the element being controlled. For example, a button might expand or collapse a list acting as a menu. The value of `aria-controls` will be the `id` of the controlled element (the menu list in this example).
:::interactive_editor
```html
<link rel="stylesheet" href="styles.css">
<button aria-expanded="false" aria-controls="menu1">Menu</button>
<ul id="menu1">
<li>...</li>
<li>...</li>
</ul>
<script src="index.js"></script>
```
```css
button {
background-color: #0078d4;
color: white;
padding: 8px 12px;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #005ea2;
}
ul {
list-style: none;
padding: 0;
margin: 8px 0 0;
border: 1px solid #ccc;
border-radius: 4px;
width: 150px;
background: #fff;
}
li {
padding: 8px;
cursor: pointer;
}
li:hover {
background-color: #f2f2f2;
}
```
```js
const button = document.querySelector('button');
const menu = document.getElementById(button.getAttribute('aria-controls'));
button.addEventListener('click', () => {
const expanded = button.getAttribute('aria-expanded') === 'true';
button.setAttribute('aria-expanded', String(!expanded));
menu.hidden = expanded;
});
```
:::
Notice that the list immediately follows the controlling button. For expandable controls like this, it is best to have the expanded content immediately follow the element that controls it in the DOM. This prevents screen reader users from having to search for the expanded content, and makes it easier for keyboard users to navigate through any interactive controls in the expanded content.
If it is not possible to place the expanded content immediately after the controlling element, the `aria-owns` attribute allows you to virtually move it after the control in the accessibility tree. This allows assistive technology like screen readers to pretend the expanded content is placed directly after the control in the DOM.
:::interactive_editor
```html
<link rel="stylesheet" href="styles.css">
<button aria-owns="menu1" aria-expanded="true">Menu</button>
<main>
<!-- an entire page worth of content --->
@@ -56,8 +115,70 @@ If it is not possible to place the expanded content immediately after the contro
<li>...</li>
<li>...</li>
</ul>
<script src="index.js"></script>
```
```css
button {
background-color: #0078d4;
color: white;
padding: 8px 12px;
border: none;
border-radius: 4px;
cursor: pointer;
margin-bottom: 10px;
}
button:hover {
background-color: #005ea2;
}
ul {
list-style: none;
padding: 0;
margin: 8px 0;
border: 1px solid #ccc;
border-radius: 4px;
width: 150px;
background: #fff;
position: absolute;
z-index: 10;
}
li {
padding: 8px;
cursor: pointer;
}
li:hover {
background-color: #f2f2f2;
}
```
```js
const button = document.querySelector('button');
const menu = document.getElementById(button.getAttribute('aria-owns'));
button.addEventListener('click', () => {
const expanded = button.getAttribute('aria-expanded') === 'true';
button.setAttribute('aria-expanded', String(!expanded));
menu.hidden = expanded;
});
// Close the menu if user clicks outside
document.addEventListener('click', (e) => {
if (!button.contains(e.target) && !menu.contains(e.target)) {
button.setAttribute('aria-expanded', 'false');
menu.hidden = true;
}
});
```
:::
There are drawbacks to using the `aria-owns` attribute. It creates unnecessary verbosity for screen reader users since most screen readers will automatically read out the entire contents of the expanded element when first expanded. It also does not change the tab order, potentially forcing keyboard users to tab through all of the other interactive controls on the page before reaching the expanded content, unless you manage the tabbing order with JavaScript.
Ideally, the expandable content should be placed after the control element, and the `aria-owns` attribute should only be used in a worst case scenario when that is not possible. If it must be used, you will need to thoroughly test with a wide range of screen readers and browsers to ensure that your implementation is accessible for everyone.