diff --git a/goldens/cdk/a11y/index.api.md b/goldens/cdk/a11y/index.api.md
index 97e249a3dbf6..64d95ac14d6c 100644
--- a/goldens/cdk/a11y/index.api.md
+++ b/goldens/cdk/a11y/index.api.md
@@ -327,6 +327,7 @@ export interface InputModalityDetectorOptions {
export class InteractivityChecker {
isDisabled(element: HTMLElement): boolean;
isFocusable(element: HTMLElement, config?: IsFocusableConfig): boolean;
+ isInert(element: HTMLElement): boolean;
isTabbable(element: HTMLElement): boolean;
isVisible(element: HTMLElement): boolean;
// (undocumented)
diff --git a/src/cdk/a11y/focus-trap/focus-trap.spec.ts b/src/cdk/a11y/focus-trap/focus-trap.spec.ts
index a196f6715273..fb584b81c9d2 100644
--- a/src/cdk/a11y/focus-trap/focus-trap.spec.ts
+++ b/src/cdk/a11y/focus-trap/focus-trap.spec.ts
@@ -54,6 +54,21 @@ describe('FocusTrap', () => {
.toBe(true);
});
+ it('should skip elements inside an inert subtree when focusing the last element', () => {
+ const fixture = TestBed.createComponent(FocusTrapWithInertLastChild);
+ fixture.detectChanges();
+
+ const result =
+ fixture.componentInstance.focusTrapDirective.focusTrap.focusLastTabbableElement();
+
+ expect(getActiveElement().id)
+ .withContext('Expected the last non-inert element to be focused')
+ .toBe('last-visible');
+ expect(result)
+ .withContext('Expected return value to be true if focus was shifted.')
+ .toBe(true);
+ });
+
it('should return false if it did not manage to find a focusable element', () => {
const fixture = TestBed.createComponent(FocusTrapWithoutFocusableElements);
fixture.detectChanges();
@@ -341,6 +356,23 @@ class SimpleFocusTrap {
@ViewChild(CdkTrapFocus) focusTrapDirective!: CdkTrapFocus;
}
+@Component({
+ template: `
+
+ `,
+ imports: [A11yModule, PortalModule],
+ changeDetection: ChangeDetectionStrategy.Eager,
+})
+class FocusTrapWithInertLastChild {
+ @ViewChild(CdkTrapFocus) focusTrapDirective!: CdkTrapFocus;
+}
+
const AUTO_FOCUS_TEMPLATE = `
@if (showTrappedRegion) {
diff --git a/src/cdk/a11y/interactivity-checker/interactivity-checker.spec.ts b/src/cdk/a11y/interactivity-checker/interactivity-checker.spec.ts
index 6e4d348d612a..e0db3cb64156 100644
--- a/src/cdk/a11y/interactivity-checker/interactivity-checker.spec.ts
+++ b/src/cdk/a11y/interactivity-checker/interactivity-checker.spec.ts
@@ -44,6 +44,40 @@ describe('InteractivityChecker', () => {
});
});
+ describe('isInert', () => {
+ it('should return true for an element with the inert attribute', () => {
+ const button = document.createElement('button');
+ button.setAttribute('inert', '');
+ testContainerElement.appendChild(button);
+
+ expect(checker.isInert(button)).withContext('Expected