diff --git a/docs/resources/changelog.md b/docs/resources/changelog.md index 95d898fd0..33167f26d 100644 --- a/docs/resources/changelog.md +++ b/docs/resources/changelog.md @@ -9,6 +9,7 @@ _During the beta period, these restrictions may be relaxed in the event of a mis ## Next - Added `tag-base`, `tag-content`, and `tag-remove-button` parts to `` [#682](https://github.com/shoelace-style/shoelace/discussions/682) +- Added support for focusing elements with `autofocus` when `` and `` open [#688](https://github.com/shoelace-style/shoelace/issues/688) - Fixed a bug that allowed `` to go into an incorrect state when activating the trigger while disabled [#684](https://github.com/shoelace-style/shoelace/pull/684) - Fixed a bug where Safari would sometimes not focus after preventing `sl-initial-focus` [#688](https://github.com/shoelace-style/shoelace/issues/688) - Improved the size of the remove button in `` diff --git a/src/components/dialog/dialog.ts b/src/components/dialog/dialog.ts index d20b2574f..6cfd91a91 100644 --- a/src/components/dialog/dialog.ts +++ b/src/components/dialog/dialog.ts @@ -139,6 +139,17 @@ export default class SlDialog extends LitElement { this.hide(); } + // Sets focus on the first child element with autofocus, falling back to the panel if one isn't found + private setInitialFocus() { + const target = this.querySelector('[autofocus]'); + + if (target) { + (target as HTMLElement).focus({ preventScroll: true }); + } else { + this.panel.focus({ preventScroll: true }); + } + } + handleKeyDown(event: KeyboardEvent) { if (event.key === 'Escape') { event.stopPropagation(); @@ -164,7 +175,7 @@ export default class SlDialog extends LitElement { requestAnimationFrame(() => { const slInitialFocus = emit(this, 'sl-initial-focus', { cancelable: true }); if (!slInitialFocus.defaultPrevented) { - this.panel.focus({ preventScroll: true }); + this.setInitialFocus(); } }); } @@ -182,7 +193,7 @@ export default class SlDialog extends LitElement { requestAnimationFrame(() => { const slInitialFocus = emit(this, 'sl-initial-focus', { cancelable: true }); if (!slInitialFocus.defaultPrevented) { - this.panel.focus(); + this.setInitialFocus(); } }); } diff --git a/src/components/drawer/drawer.ts b/src/components/drawer/drawer.ts index 350bce0f8..0d7cd34ee 100644 --- a/src/components/drawer/drawer.ts +++ b/src/components/drawer/drawer.ts @@ -156,6 +156,17 @@ export default class SlDrawer extends LitElement { this.hide(); } + // Sets focus on the first child element with autofocus, falling back to the panel if one isn't found + private setInitialFocus() { + const target = this.querySelector('[autofocus]'); + + if (target) { + (target as HTMLElement).focus({ preventScroll: true }); + } else { + this.panel.focus({ preventScroll: true }); + } + } + handleKeyDown(event: KeyboardEvent) { if (event.key === 'Escape') { event.stopPropagation(); @@ -184,7 +195,7 @@ export default class SlDrawer extends LitElement { requestAnimationFrame(() => { const slInitialFocus = emit(this, 'sl-initial-focus', { cancelable: true }); if (!slInitialFocus.defaultPrevented) { - this.panel.focus({ preventScroll: true }); + this.setInitialFocus(); } }); } @@ -202,7 +213,7 @@ export default class SlDrawer extends LitElement { requestAnimationFrame(() => { const slInitialFocus = emit(this, 'sl-initial-focus', { cancelable: true }); if (!slInitialFocus.defaultPrevented) { - this.panel.focus(); + this.setInitialFocus(); } }); }