diff --git a/curriculum/challenges/english/blocks/lecture-understanding-aria-expanded-aria-live-and-common-aria-states/672a5507d857a891139abc7f.md b/curriculum/challenges/english/blocks/lecture-understanding-aria-expanded-aria-live-and-common-aria-states/672a5507d857a891139abc7f.md
index dabe998e704..ecd2e1e1f39 100644
--- a/curriculum/challenges/english/blocks/lecture-understanding-aria-expanded-aria-live-and-common-aria-states/672a5507d857a891139abc7f.md
+++ b/curriculum/challenges/english/blocks/lecture-understanding-aria-expanded-aria-live-and-common-aria-states/672a5507d857a891139abc7f.md
@@ -5,14 +5,16 @@ challengeType: 19
dashedName: what-is-the-aria-controls-attribute
---
-# --description--
+# --interactive--
The `aria-controls` attribute is used to create a programmatic relationship between an element that controls the presence of another element on the page, and the element it controls. This relationship can help screen reader users better understand how the control works. Common uses include a set of tabs that control the visibility of different sections of content, or a button that toggles the visibility of a menu.
-Let's take a look at an example to see how this works.
-In this example of a tabbed interface, we have a `div` element with a set of three buttons:
+Let's take a look at an example to see how this works. In this example of a tabbed interface, we have a `div` element with a set of three buttons:
+
+:::interactive_editor
```html
+
```
+```css
+[role="tablist"] {
+ display: flex;
+ border-bottom: 2px solid #ccc;
+ margin-bottom: 1em;
+ gap: 4px;
+}
+
+[role="tab"] {
+ background: #f5f5f5;
+ border: 1px solid #ccc;
+ border-bottom: none;
+ border-radius: 4px 4px 0 0;
+ padding: 8px 16px;
+ cursor: pointer;
+ font-size: 14px;
+ color: #333;
+ transition: background 0.2s, color 0.2s;
+}
+
+[role="tab"]:hover,
+[role="tab"]:focus {
+ background: #e8f0fe;
+ outline: none;
+}
+
+[role="tab"][aria-selected="true"] {
+ background: #fff;
+ border-color: #ccc;
+ border-bottom: 2px solid #fff;
+ color: #000;
+ font-weight: 600;
+ position: relative;
+ top: 1px;
+}
+
+[role="tab"]:focus-visible {
+ outline: 2px solid #0078d4;
+ outline-offset: 2px;
+}
+
+```
+
+:::
+
The `div` uses `role="tablist"` to indicate that it serves as a container element for a group of tabs.
Each button represents a tab and has a `role` attribute set to `tab`. In most tabbed interfaces, the first tab panel is visible by default, so the first tab button has an `aria-selected` attribute set to `true` to indicate that its associated section of content is currently visible. The `aria-controls` attribute is used to associate each button with the section of content that it controls.
Here are the three sections of content that correspond to the tabs:
+:::interactive_editor
+
```html
+
+
+
+
+
+
+
Section 1 content
@@ -44,8 +106,122 @@ Here are the three sections of content that correspond to the tabs:
Section 3 content
+
```
+```css
+[role="tablist"] {
+ display: flex;
+ border-bottom: 2px solid #ccc;
+ margin-bottom: 1em;
+ gap: 4px;
+ background: #fafafa;
+ padding: 0.25em;
+}
+
+[role="tab"] {
+ background: #f5f5f5;
+ border: 1px solid #ccc;
+ border-bottom: none;
+ border-radius: 4px 4px 0 0;
+ padding: 8px 16px;
+ cursor: pointer;
+ font-size: 14px;
+ color: #333;
+ transition: background 0.2s, color 0.2s;
+}
+
+[role="tab"]:hover,
+[role="tab"]:focus {
+ background: #e8f0fe;
+ outline: none;
+}
+
+[role="tab"][aria-selected="true"] {
+ background: #fff;
+ border-color: #ccc;
+ border-bottom: 2px solid #fff;
+ color: #000;
+ font-weight: 600;
+ position: relative;
+ top: 1px;
+}
+
+[role="tab"]:focus-visible {
+ outline: 2px solid #0078d4;
+ outline-offset: 2px;
+}
+
+[role="tabpanel"] {
+ border: 1px solid #ccc;
+ border-radius: 0 4px 4px 4px;
+ padding: 16px;
+ background-color: #fff;
+ color: #333;
+ font-size: 15px;
+ line-height: 1.4;
+}
+
+[role="tabpanel"][hidden] {
+ display: none;
+}
+
+```
+
+```js
+const tabs = document.querySelectorAll('[role="tab"]');
+const tabList = document.querySelector('[role="tablist"]');
+
+tabs.forEach(tab => {
+ tab.addEventListener('click', () => {
+ activateTab(tab);
+ });
+
+ tab.addEventListener('keydown', (e) => {
+ const key = e.key;
+ const currentIndex = Array.from(tabs).indexOf(tab);
+ let newIndex = null;
+
+ if (key === 'ArrowRight') {
+ newIndex = (currentIndex + 1) % tabs.length;
+ } else if (key === 'ArrowLeft') {
+ newIndex = (currentIndex - 1 + tabs.length) % tabs.length;
+ } else if (key === 'Home') {
+ newIndex = 0;
+ } else if (key === 'End') {
+ newIndex = tabs.length - 1;
+ }
+
+ if (newIndex !== null) {
+ tabs[newIndex].focus();
+ activateTab(tabs[newIndex]);
+ }
+ });
+});
+
+function activateTab(tab) {
+ const tabPanels = document.querySelectorAll('[role="tabpanel"]');
+
+ tabs.forEach(t => {
+ t.setAttribute('aria-selected', 'false');
+ t.setAttribute('tabindex', '-1');
+ });
+
+ tabPanels.forEach(panel => panel.hidden = true);
+
+ tab.setAttribute('aria-selected', 'true');
+ tab.removeAttribute('tabindex');
+
+ const panelId = tab.getAttribute('aria-controls');
+ const panel = document.getElementById(panelId);
+ panel.hidden = false;
+ tab.focus();
+}
+
+```
+
+:::
+
Each section of content has a `role` attribute set to `tabpanel` and an `aria-labelledby` attribute that points to the corresponding tab to give the panel an accessible name. The `hidden` attribute is used to hide the sections of content that are not currently selected. Each section ID matches the value of the `aria-controls` attribute on the corresponding button. The `section1` ID matches the `aria-controls` attribute on the first button, `section2` matches the `aria-controls` attribute on the second button, and `section3` matches the `aria-controls` attribute on the third button. This is how the association between the tabs and their sections of content is established.
To switch between the different sections you will need to use JavaScript to update the `hidden` attribute on the section and the `aria-selected` attribute on the button based on which section is currently visible. Only one section can be visible at a time and it should not have the `hidden` attribute and `aria-selected` should be set to `true` on its button. The remaining hidden sections should all have the `hidden` attribute and `aria-selected` should be set to `false` on their buttons.