Skip to main content
HTML Validation

Bad value “” for attribute “aria-controls” on element “a”: An IDREFS value must contain at least one non-whitespace character.

About This HTML Issue

The aria-controls attribute establishes a programmatic relationship between an interactive element (like a button or link) and the content it controls. Assistive technologies such as screen readers use this relationship to help users navigate between a control and the region it affects—for example, a button that toggles a panel or a tab that switches visible content. When the attribute is present but empty (aria-controls=""or aria-controls=" "), it signals a broken relationship: the browser and assistive technology expect a target element but find nothing.

This issue commonly occurs when aria-controls is added by a JavaScript framework or template before the target element's id is known, leaving behind an empty placeholder. It can also happen when a CMS or component library outputs the attribute unconditionally, even when no controlled region exists.

Why this matters

  • Accessibility: Screen readers may announce that a control is associated with another element, but an empty reference leads nowhere. This creates a confusing or misleading experience for users who rely on assistive technology.
  • Standards compliance: The HTML specification defines aria-controls as an IDREFS attribute, meaning its value must contain one or more space-separated tokens, each matching the id of an element in the same document. An empty value is invalid per both the WAI-ARIA specification and the HTML standard.
  • Maintainability: Empty or placeholder ARIA attributes are a sign of incomplete implementation. They can mask bugs in dynamic UIs where the controlled element was supposed to be rendered but wasn't, or where an id was accidentally removed during refactoring.

How to fix it

  1. If the element controls another region, set aria-controls to the id of that region. Make sure the target element exists in the DOM and has a unique id.
  2. If the element doesn't control anything, remove the aria-controls attribute entirely. An absent attribute is always better than an empty one.
  3. For dynamically rendered content, only add aria-controls after the target element and its id are present in the DOM. If using a framework, conditionally render the attribute.
  4. Keep references in sync. If you rename or remove an id, update every aria-controls that references it.

Examples

Invalid: empty aria-controls

This triggers the validator error because the attribute value contains no id reference.

<a href="#" aria-controls="">Toggle details</a>

Invalid: whitespace-only value

A value with only spaces is also invalid—IDREFS requires at least one non-whitespace token.

<button type="button" aria-controls="   ">Open menu</button>

Fixed: provide a valid id reference

Point aria-controls to the id of the element being controlled.

<button type="button" aria-controls="details-panel" aria-expanded="false">
  Toggle details
</button>
<div id="details-panel" hidden>
  <p>Here are some additional details.</p>
</div>

Fixed: controlling multiple regions

You can reference multiple id values separated by spaces. Each id must correspond to an element in the document.

<button type="button" aria-controls="filters results">
  Show filters and results
</button>
<section id="filters" hidden>
  <p>Filter options...</p>
</section>
<section id="results" hidden>
  <p>Search results...</p>
</section>

Fixed: remove the attribute when not needed

If the element doesn't actually control another region, simply omit aria-controls.

<a href="/details">View details</a>

Complete document with proper toggle behavior

This example shows a working toggle pattern combining aria-controls with aria-expanded for full accessibility.

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>aria-controls Toggle Example</title>
  </head>
  <body>
    <button type="button" aria-controls="info-panel" aria-expanded="false">
      Toggle info
    </button>
    <div id="info-panel" hidden>
      <p>Extra information goes here.</p>
    </div>
    <script>
      const btn = document.querySelector('button');
      const panel = document.getElementById('info-panel');
      btn.addEventListener('click', () => {
        const expanded = btn.getAttribute('aria-expanded') === 'true';
        btn.setAttribute('aria-expanded', String(!expanded));
        panel.hidden = expanded;
      });
    </script>
  </body>
</html>

Conditional rendering in a framework

When using a templating system or JavaScript framework, only render aria-controls when the target id is available. Here's a conceptual example:

<!-- Good: only add the attribute when targetId has a value -->
<button type="button" aria-controls="sidebar-nav" aria-expanded="false">
  Menu
</button>
<nav id="sidebar-nav" hidden>
  <ul>
    <li><a href="/">Home</a></li>
  </ul>
</nav>

<!-- Bad: template outputs an empty value when targetId is undefined -->
<!-- <button type="button" aria-controls="">Menu</button> -->

In frameworks like React, you can conditionally spread the attribute: use aria-controls={targetId || undefined} so that when the value is empty, the attribute is omitted from the rendered HTML entirely rather than being set to an empty string.

Find issues like this automatically

Rocket Validator scans thousands of pages in seconds, detecting HTML issues across your entire site.

Help us improve our guides

Was this guide helpful?
🌍 Trusted by teams worldwide

Validate at scale.
Ship accessible websites, faster.

Automated HTML & accessibility validation for large sites. Check thousands of pages against WCAG guidelines and W3C standards in minutes, not days.

Scheduled Reports
API Access
Open Source Standards
$7 / 7 days

Pro Trial

Full Pro access. Cancel anytime.

Start Pro Trial →

Join teams across 40+ countries