#6104·heroui

[v3] Tabs component ARIA violations (aria-valid-attr-value, nested-interactive)

Author: cloud-devops-expertCreated Jan 12, 2026Updated Aug 16, 2026

Description

HeroUI v3.0.0-beta.3 Tabs component has ARIA attribute violations detected by axe-core that block WCAG 2.1 Level A compliance.

Violations

1. Invalid aria-controls Reference (aria-valid-attr-value)

Severity: Critical (WCAG 2.1 Level A - 4.1.2 Name, Role, Value)

The Tabs component generates aria-controls attributes that reference non-existent IDs:

xml
<div data-slot="tabs-tab" 
     role="tab"
     aria-controls="react-aria-_r_1_-tabpanel-availability"
     aria-selected="true">
  Availability
</div>

Issue: The ID react-aria-_r_1_-tabpanel-availability does not exist in the DOM.

axe-core error:

ARIA attributes must conform to valid values (aria-valid-attr-value)
Invalid ARIA attribute value: aria-controls="react-aria-_r_1_-tabpanel-availability"

2. Nested Interactive Controls (nested-interactive)

Severity: Moderate (keyboard navigation confusion)

Popover triggers inside tab panels have focusable descendants, creating nested interactive elements:

xml
<div class="popover__trigger"
     role="button"
     aria-expanded="false"
     data-react-aria-pressable="true"
     tabindex="0">
  <button ...> <!-- Nested button inside button-like element -->

axe-core error:

Interactive controls must not be nested (nested-interactive)
Fix any of the following:
  Element has focusable descendants

Impact

  • Screen Readers: ARIA controls mismatch causes incorrect tab panel announcements
  • Keyboard Navigation: Nested interactive controls create focus traps
  • WCAG Compliance: Fails WCAG 2.1 Level A (4.1.2 Name, Role, Value)
  • Production Blocker: Cannot deploy accessibility-compliant applications with these violations

Reproduction

typescript
import { Tabs, Tab } from '@heroui/react';

<Tabs defaultSelectedKey="availability" variant="bordered">
  <Tab key="availability" title="Availability">
    Content 1
  </Tab>
  <Tab key="attempts" title="Attempts">
    Content 2
  </Tab>
</Tabs>

Run axe-core accessibility tests:

typescript
import { axe } from 'jest-axe';

it('should have no accessibility violations', async () => {
  const { container } = render(<MyTabsComponent />);
  const results = await axe(container);
  expect(results).toHaveNoViolations(); // ❌ Fails
});

Environment

  • HeroUI: v3.0.0-beta.3
  • React: 19.2.1
  • Next.js: 16.0.10
  • Node: 22.0.0
  • axe-core: 4.10.x

Expected Behavior

  1. aria-controls attribute should reference actual tabpanel IDs that exist in the DOM
  2. Popover triggers should not have nested focusable elements

Workaround

Using React Aria Tabs directly until HeroUI v3 fix is available:

typescript
import { Tabs, TabList, Tab, TabPanel } from 'react-aria-components';

<Tabs defaultSelectedKey="availability">
  <TabList>
    <Tab id="availability">Availability</Tab>
    <Tab id="attempts">Attempts</Tab>
  </TabList>
  <TabPanel id="availability">Content 1</TabPanel>
  <TabPanel id="attempts">Content 2</TabPanel>
</Tabs>

References

Additional Context

This blocks production deployment for applications requiring WCAG 2.1 Level A accessibility compliance. React Aria (the foundation of HeroUI v3) has proper ARIA implementations - this appears to be a wrapper issue in HeroUI v3.