Skip to content

fix(material/bottom-sheet): page jumping if backdrop-filter is applied #30840

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions goldens/cdk/dialog/index.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export class CdkDialogContainer<C extends DialogConfig = DialogConfig> extends B
// (undocumented)
protected _document: Document;
// (undocumented)
protected _elementRef: ElementRef<any>;
protected _elementRef: ElementRef<HTMLElement>;
// (undocumented)
protected _focusTrapFactory: FocusTrapFactory;
// (undocumented)
Expand All @@ -69,7 +69,7 @@ export class CdkDialogContainer<C extends DialogConfig = DialogConfig> extends B
_recaptureFocus(): void;
// (undocumented)
_removeAriaLabelledBy(id: string): void;
protected _trapFocus(): void;
protected _trapFocus(options?: FocusOptions): void;
// (undocumented)
static ɵcmp: i0.ɵɵComponentDeclaration<CdkDialogContainer<any>, "cdk-dialog-container", never, {}, {}, never, never, true, never>;
// (undocumented)
Expand Down
2 changes: 2 additions & 0 deletions goldens/material/bottom-sheet/index.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ export class MatBottomSheetContainer extends CdkDialogContainer implements OnDes
// (undocumented)
ngOnDestroy(): void;
// (undocumented)
protected _trapFocus(): void;
// (undocumented)
static ɵcmp: i0.ɵɵComponentDeclaration<MatBottomSheetContainer, "mat-bottom-sheet-container", never, {}, {}, never, never, true, never>;
// (undocumented)
static ɵfac: i0.ɵɵFactoryDeclaration<MatBottomSheetContainer, never>;
Expand Down
18 changes: 9 additions & 9 deletions src/cdk/dialog/dialog-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export class CdkDialogContainer<C extends DialogConfig = DialogConfig>
extends BasePortalOutlet
implements OnDestroy
{
protected _elementRef = inject(ElementRef);
protected _elementRef = inject<ElementRef<HTMLElement>>(ElementRef);
protected _focusTrapFactory = inject(FocusTrapFactory);
readonly _config: C;
private _interactivityChecker = inject(InteractivityChecker);
Expand Down Expand Up @@ -254,7 +254,7 @@ export class CdkDialogContainer<C extends DialogConfig = DialogConfig>
* Moves the focus inside the focus trap. When autoFocus is not set to 'dialog', if focus
* cannot be moved then focus will go to the dialog container.
*/
protected _trapFocus() {
protected _trapFocus(options?: FocusOptions) {
if (this._isDestroyed) {
return;
}
Expand All @@ -274,23 +274,23 @@ export class CdkDialogContainer<C extends DialogConfig = DialogConfig>
// if the focus isn't inside the dialog already, because it's possible that the consumer
// turned off `autoFocus` in order to move focus themselves.
if (!this._containsFocus()) {
element.focus();
element.focus(options);
}
break;
case true:
case 'first-tabbable':
const focusedSuccessfully = this._focusTrap?.focusInitialElement();
const focusedSuccessfully = this._focusTrap?.focusInitialElement(options);
// If we weren't able to find a focusable element in the dialog, then focus the dialog
// container instead.
if (!focusedSuccessfully) {
this._focusDialogContainer();
this._focusDialogContainer(options);
}
break;
case 'first-heading':
this._focusByCssSelector('h1, h2, h3, h4, h5, h6, [role="heading"]');
this._focusByCssSelector('h1, h2, h3, h4, h5, h6, [role="heading"]', options);
break;
default:
this._focusByCssSelector(this._config.autoFocus!);
this._focusByCssSelector(this._config.autoFocus!, options);
break;
}
},
Expand Down Expand Up @@ -345,10 +345,10 @@ export class CdkDialogContainer<C extends DialogConfig = DialogConfig>
}

/** Focuses the dialog container. */
private _focusDialogContainer() {
private _focusDialogContainer(options?: FocusOptions) {
// Note that there is no focus method when rendering on the server.
if (this._elementRef.nativeElement.focus) {
this._elementRef.nativeElement.focus();
this._elementRef.nativeElement.focus(options);
}
}

Expand Down
9 changes: 9 additions & 0 deletions src/material/bottom-sheet/bottom-sheet-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,15 @@ export class MatBottomSheetContainer extends CdkDialogContainer implements OnDes
});
}

protected override _trapFocus(): void {
// The bottom sheet starts off-screen and animates in, and at the same time we trap focus
// within it. With some styles this appears to cause the page to jump around. See:
// https://github.com/angular/components/issues/30774. Preventing the browser from
// scrolling resolves the issue and isn't really necessary since the bottom sheet
// normally isn't scrollable.
super._trapFocus({preventScroll: true});
}

protected _handleAnimationEvent(isStart: boolean, animationName: string) {
const isEnter = animationName === ENTER_ANIMATION;
const isExit = animationName === EXIT_ANIMATION;
Expand Down
Loading