Skip to content

feat(FocusMonitor): Add optional checkActiveDescendant option to FocusMonitor.monitor #21555

Open
@zelliott

Description

@zelliott

Feature Description

Today, FocusMonitor listens for focus changes and attributes them to a particular input modality. It would also be useful to be able to listen for changes in aria-activedescendant changes and attribute them appropriately as well. To support this, we can extend FocusMonitor.monitor with an optional checkActiveDescendant parameter that, when true, will listen for changes in the focused element's aria-activedescendant property with a MutationObserver.

Use Case

In my app, we render strong keyboard focus indicators only on keyboard focus. We determine this by attaching a FocusMonitor to body with checkChildren = true. When the class .cdk-keyboard-focused is present on the body, we know that keyboard input modality has been detected.

This works for most cases. However, consider the following scenario with the MatAutocomplete component.

  1. User clicks on MatAutocomplete input.
  2. Autocomplete options render below the input.
  3. User presses down arrow to navigate to the first option.

At step 1, we do not want to render a strong focus indicator (as the user is interacting with mouse). At step 3, we do want to render a strong focus indicator on the first option (as the user is now interacting with keyboard). However, FocusMonitor does not support this scenario today, as no focus change has occurred. Instead, the aria-activedescendant on the focused <input /> element has updated. We want to be able to detect this change.

Implementation Details

I'm thinking we can support this in FocusMonitor via the following changes:

  • On FocusMonitor._onFocus, create a new MutationObserver that listens for aria-activedescendant changes on the focused element (if checkActiveDescendant is true). Additionally, if a created MutationObserver already exists, disconnect the existing observer. This means that there should only ever be one MutationObserver at any point in time, as we only need to observe the document.activeElement. This also means that if aria-activedescendant changes on an element that is not focused, this will not be detected (I think this is fine).
  • When the observer callback is fired, update the focus origin accordingly.
  • On FocusMonitor._onBlur, disconnect the existing observer (again if checkActiveDescendant is true).

Metadata

Metadata

Assignees

No one assigned

    Labels

    GThis is is related to a Google internal issueP3An issue that is relevant to core functions, but does not impede progress. Important, but not urgentarea: cdk/a11yfeatureThis issue represents a new feature or feature request rather than a bug or bug fixneeds: discussionFurther discussion with the team is needed before proceeding

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions