# The “aria-controls” attribute must point to an element in the same document.

> Canonical HTML version: https://rocketvalidator.com/html-validation/the-aria-controls-attribute-must-point-to-an-element-in-the-same-document
> Attribution: Rocket Validator (https://rocketvalidator.com)
> License: CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)

The `aria-controls` attribute establishes a programmatic relationship between a controlling element (like a button, tab, or scrollbar) and the element it controls (like a panel, region, or content area). Assistive technologies such as screen readers use this relationship to help users navigate between related elements — for example, announcing that a button controls a specific panel and allowing the user to jump to it.

When the `id` referenced in `aria-controls` doesn't exist in the document, the relationship is broken. Screen readers may attempt to locate the target element and fail silently, or they may announce a control relationship that leads nowhere. This degrades the experience for users who rely on assistive technology and violates the [WAI-ARIA specification](https://www.w3.org/TR/wai-aria-1.2/#aria-controls), which requires that the value of `aria-controls` be a valid ID reference list pointing to elements in the same document.

Common causes of this error include:

- **Typos** in the `id` or the `aria-controls` value.
- **Dynamically generated content** where the controlled element hasn't been rendered yet or has been removed from the DOM.
- **Copy-paste errors** where `aria-controls` was copied from another component but the corresponding `id` was not updated.
- **Referencing elements in iframes or shadow DOM**, which are considered separate document contexts.

The `aria-controls` attribute accepts one or more space-separated ID references. Every listed ID must match an element in the same document.

## How to Fix

1. **Verify the target element exists** in the document and has the exact `id` that `aria-controls` references.
2. **Check for typos** — ID matching is case-sensitive, so `mainPanel` and `mainpanel` are not the same.
3. **If the controlled element is added dynamically**, ensure it is present in the DOM before or at the same time as the controlling element, or update `aria-controls` programmatically when the target becomes available.
4. **If the controlled element is genuinely absent** (e.g., conditionally rendered), remove the `aria-controls` attribute until the target element exists.

## Examples

### Incorrect: `aria-controls` references a non-existent ID

```html
<button aria-controls="info-panel" aria-expanded="false">
  Toggle Info
</button>

<div id="infopanel">
  <p>Here is some additional information.</p>
</div>
```

This triggers the error because `aria-controls="info-panel"` does not match the actual `id` of `"infopanel"` (note the missing hyphen).

### Correct: `aria-controls` matches an existing element's ID

```html
<button aria-controls="info-panel" aria-expanded="false">
  Toggle Info
</button>

<div id="info-panel">
  <p>Here is some additional information.</p>
</div>
```

### Correct: Tab and tab panel relationship

```html
<div role="tablist">
  <button role="tab" aria-controls="tab1-panel" aria-selected="true">
    Overview
  </button>
  <button role="tab" aria-controls="tab2-panel" aria-selected="false">
    Details
  </button>
</div>

<div id="tab1-panel" role="tabpanel">
  <p>Overview content goes here.</p>
</div>

<div id="tab2-panel" role="tabpanel" hidden>
  <p>Details content goes here.</p>
</div>
```

Both `aria-controls` values — `tab1-panel` and `tab2-panel` — correctly correspond to elements present in the document.

### Correct: Custom scrollbar controlling a region

```html
<div role="scrollbar" aria-controls="main-content" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" aria-orientation="vertical"></div>

<div id="main-content" role="region" aria-label="Main content">
  <p>Scrollable content goes here.</p>
</div>
```

### Correct: Controlling multiple elements

The `aria-controls` attribute can reference multiple IDs separated by spaces. Each ID must exist in the document.

```html
<button aria-controls="section-a section-b">
  Expand All Sections
</button>

<div id="section-a">
  <p>Section A content.</p>
</div>

<div id="section-b">
  <p>Section B content.</p>
</div>
```
