Vibe Check – Why aria-describedby
and other ARIA attributes don’t always work in Shadow DOM
ARIA (Accessible Rich Internet Applications
) attributes are powerful tools for improving accessibility, but they have limitations—especially when used inside the Shadow DOM. Many designers and developers assume that aria-labelledby
and aria-describedby
will work seamlessly across Shadow DOM boundaries, only to discover that assistive technologies can’t access referenced elements outside their Shadow Roots.
Not all ARIA attributes fail in the Shadow DOM, but those that rely on referencing elements outside the Shadow Root often break. Let’s explore why this happens and how to fix it.
A personal story – When ARIA failed inside the Shadow DOM
I once worked on a project that relied heavily on custom web components. We designed accessible modals, tooltips, and input fields—all following best practices. Everything had clear labels, descriptions, and appropriate aria-describedby
references.
But when we tested with a screen reader, the descriptions weren’t being announced. Forms inside the Shadow DOM had error messages, but screen readers ignored them. Tooltips linked with aria-describedby
didn’t work either.
After hours of debugging, we found the issue: ARIA attributes don’t always pierce the Shadow DOM. If a label or description is outside the Shadow Root, assistive technology won’t recognize it. That realization changed how we approached accessibility for web components.
Elevate the vibe – Why ARIA attributes don’t work across Shadow DOM boundaries
1) Shadow DOM creates an isolated accessibility tree
The problem:
The Shadow DOM forms its own separate accessibility tree, meaning elements inside it cannot reference elements outside of it using ARIA attributes.
If aria-labelledby
or aria-describedby
points to an ID outside the Shadow DOM, assistive technologies ignore it.
What happens?
<input aria-describedby="error-message">
will work only if #error-message
is inside the same Shadow Root.
If #error-message
exists in the Light DOM, the screen reader won’t make the connection.
Fix it:
Place all referenced labels and descriptions inside the same Shadow Root as the element they describe.
If external references are needed, use alternative methods like slotting content into the Shadow DOM.
2) Some ARIA attributes still work in Shadow DOM
Not all ARIA fails in Shadow DOM! Attributes that apply to the element itself still function correctly.
What works:
role
attributes (e.g., role="button"
, role="dialog"
).
ARIA states (aria-disabled
, aria-expanded
, aria-checked
).
aria-live
(as long as the live region is inside the same Shadow Root).
What doesn’t work across Shadow DOM boundaries:
aria-labelledby
and aria-describedby
(if referencing an external element).
aria-controls
(if controlling an element outside the Shadow DOM).
aria-activedescendant
(if pointing to an element outside the Shadow DOM).
3) Tooltips and error messages may not be announced
The problem:
Many custom components rely on tooltips or inline error messages that use aria-describedby
.
If these messages exist outside the Shadow DOM, assistive technologies won’t associate them correctly.
Fix it:
Keep error messages inside the Shadow Root with the input field.
If external text is required, consider dynamically cloning or slotting it into the Shadow DOM.
4) Focus management and ARIA live regions may break
The problem:
aria-live
elements outside the Shadow DOM won’t notify screen readers about updates inside it.
Focus may shift unpredictably when navigating between Light DOM and Shadow DOM components.
Fix it:
Use Shadow DOM-friendly focus management with tabindex
and manual event handling.
Place aria-live
elements inside the Shadow DOM so they announce changes correctly.
Vibe boost – How to make Shadow DOM components accessible
1) Keep ARIA references inside the same Shadow Root
Instead of referencing an external ID, ensure labels and descriptions exist inside the same component.
Example of broken ARIA:
<custom-input aria-describedby="error-message"></custom-input>
<span id="error-message">Invalid input</span> <!-- Won't be recognized inside Shadow DOM -->
Example of fixed ARIA:
<custom-input>
<span slot="error" id="error-message">Invalid input</span>
</custom-input>
2) Use slot
elements to expose necessary content
If descriptions or labels exist in the Light DOM, slot them inside the Shadow DOM.
Example:
<custom-button>
<span slot="label">Submit</span>
</custom-button>
3) Provide explicit labeling within components
Avoid relying on external IDs for aria-labelledby
and aria-describedby
.
Use <label>
elements inside the Shadow Root.
4) Test with assistive technology
Verify components with screen readers (NVDA, JAWS, VoiceOver).
Check keyboard focus order to ensure navigation is smooth.
Ensure error messages and descriptions are properly announced.
Self-reflection – Evaluating your use of ARIA in Shadow DOM
Ask yourself:
Are aria-labelledby
and aria-describedby
referencing elements inside the same Shadow Root?
Have I tested my web components with a screen reader?
Do my tooltips, error messages, and labels work without external dependencies?
Am I using slots to expose necessary content to assistive technology?
If any of these raise concerns, it’s time to rethink your ARIA implementation!
Vibe in action – Making ARIA work with Shadow DOM
1) Apply what you’ve learned
Audit components to remove broken ARIA references.
Ensure that error messages and labels are contained within the Shadow DOM.
2) Share the knowledge
Educate teams about ARIA limitations inside Shadow DOM.
Advocate for designing accessible components from the start.
3) Keep learning
Follow WCAG guidelines and best practices for ARIA in Shadow DOM.
Stay updated on browser improvements for web component accessibility.
Vibing out
ARIA is an essential tool for web accessibility, but it doesn’t automatically work across Shadow DOM boundaries. Understanding these limitations helps designers and developers build truly inclusive experiences.
By keeping ARIA attributes inside the Shadow Root, using slots for necessary content, and testing with assistive technology, we can ensure that web components remain functional, usable, and accessible to all.
Because when accessibility is built into the foundation, everyone benefits.
Support my work in accessibility
Creating accessible content takes time, care, and deep testing — and I love every minute of it. From writing blog posts to doing live audits and building checklists, everything I create is designed to make the digital world more inclusive.If something here helped you — whether it saved you time, taught you something new, or gave you insight into accessibility — consider supporting my work.
You can buy me a coffee to help keep this platform going strong:
Buy Me a Coffee
Every coffee goes toward:
- Creating new articles with accessibility tips, tools, and testing methods
- Covering hosting, software, and assistive tech costs
- Supporting free education for designers, developers, and testers
- Making a meaningful difference for people living with disabilities
Thanks for being part of this mission to build a more accessible web — one page at a time.