Skip to content

QDialog backdrop element rendered with conflicting aria-hidden="true" and tabindex="-1", producing a console accessibility warning #18314

@ecore78

Description

@ecore78

What happened?

When a QDialog opens in modal mode (non-seamless), its backdrop element (.q-dialog__backdrop) is rendered with both aria-hidden="true" and tabindex="-1" at the same time. During the open transition, Quasar's focus management blurs the previously focused element and then attempts to focus the dialog's inner content. However, the focus can land on the backdrop element, which is both focusable (due to tabindex="-1") and hidden from assistive technology (due to aria-hidden="true").

The browser detects this contradiction and emits the following console warning:

Blocked aria-hidden on an element because its descendant retained focus.
The focus must not be hidden from assistive technology users.
Avoid using aria-hidden on a focused element or its ancestor.
Consider using the inert attribute instead, which will also prevent focus.
For more details, see the aria-hidden section of the WAI-ARIA specification
at https://w3c.github.io/aria/#aria-hidden.

Element with focus: <div.q-dialog__backdrop fixed-full ...>
Ancestor with aria-hidden: <div.q-dialog__backdrop fixed-full ... aria-hidden="true" tabindex="-1">

The browser functionally overrides the aria-hidden (so there is no actual accessibility breakage), but the console warning is noisy and causes unnecessary concern for developers using Quasar.

What did you expect to happen?

The backdrop element should not have conflicting attributes. The expected behavior is one of:

  • Option A (recommended): Remove aria-hidden="true" from the backdrop entirely. The backdrop is an internal visual component of the dialog, not background content that should be hidden from assistive technology. Keep tabindex="-1" for programmatic focus during transitions.
  • Option B: Replace aria-hidden="true" with the [inert](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inert) attribute, which natively prevents focus while also hiding content from AT — avoiding the contradiction entirely.
  • Option C: Keep aria-hidden="true" but remove tabindex="-1" so the backdrop cannot receive programmatic focus.

No console warning should appear under normal dialog open/close cycles.

Reproduction URL

none

How to reproduce?

  1. Create a QDialog with v-model bound to a boolean ref, without seamless prop (default modal mode).
  2. Open the dialog by setting the v-model to true (programmatically or via user click).
  3. Open the browser's developer console.
  4. Observe the "Blocked aria-hidden on an element because its descendant retained focus" warning.

This is also reproducible with persistent dialogs: clicking the backdrop triggers the shake() animation, which re-focuses the dialog and can land focus on the backdrop element again, re-triggering the warning.

Flavour

Quasar CLI with Vite (@quasar/cli | @quasar/app-vite)

Areas

Components (quasar)

Platforms/Browsers

Electron

Quasar info output

Relevant log output

Additional context

  • Root cause location: In ui/src/components/dialog/QDialog.js, the renderPortalContent() function hardcodes both attributes on the backdrop element:
    h('div', {
      class: 'q-dialog__backdrop fixed-full',
      'aria-hidden': 'true',
      tabindex: -1,
      onClick: onBackdropClick
    })
  • Confirmed present in latest dev branch (commit 9dcc6fc, Apr 30, 2026) — the issue has not been fixed upstream.
  • The handleShow() method calls document.activeElement?.blur() followed by registerTick(focus), and focus() calls node.focus({ preventScroll: true }) on the dialog's innerRef. During the Vue transition, the innerRef may not yet contain focusable children, so focus falls onto the backdrop element.
  • This combination is explicitly prohibited by the [WAI-ARIA 1.2 specification](https://w3c.github.io/aria/#aria-hidden):

    "Authors MUST NOT set aria-hidden="true" on a focused element or any of its ancestors."

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions