diff --git a/.changeset/rich-apricots-argue.md b/.changeset/rich-apricots-argue.md
new file mode 100644
index 000000000..0b2622783
--- /dev/null
+++ b/.changeset/rich-apricots-argue.md
@@ -0,0 +1,5 @@
+---
+'@lion/ui': patch
+---
+
+lion-select-rich: when the overlay is shown, the "autofocus" attribute is added to \_listboxNode (\_inputNode) to make sure that keyboard navigation continues to work when the element is inside a an element with `trapsKeyboardFocus:true`, like the bottomsheet created via `withBottomSheetConfig()`. When the overlay is closed the attribute is removed.
diff --git a/packages/ui/components/select-rich/src/LionSelectRich.js b/packages/ui/components/select-rich/src/LionSelectRich.js
index 4681eb636..560b7ee7b 100644
--- a/packages/ui/components/select-rich/src/LionSelectRich.js
+++ b/packages/ui/components/select-rich/src/LionSelectRich.js
@@ -369,6 +369,11 @@ export class LionSelectRich extends SlotMixin(ScopedElementsMixin(OverlayMixin(L
if (this.hasNoDefaultSelected) {
this._noDefaultSelectedInheritsWidth();
}
+
+ // When `trapsKeyboardFocus:true` is configured in our overlay, we need to make sure
+ // that our element with [role=listbox] gets focus. The `containFocus` util will look
+ // for an element with [autofocus] (otherwise it sets focus to `contentNode` (the 'root' of the overlay))
+ this._listboxNode.setAttribute('autofocus', '');
}
/** @private */
@@ -382,6 +387,7 @@ export class LionSelectRich extends SlotMixin(ScopedElementsMixin(OverlayMixin(L
/** @private */
__overlayOnHide() {
this._invokerNode.focus();
+ this._listboxNode.removeAttribute('autofocus');
}
/**
diff --git a/packages/ui/components/select-rich/test/lion-select-rich.test.js b/packages/ui/components/select-rich/test/lion-select-rich.test.js
index cd6d2a77b..2e74a806f 100644
--- a/packages/ui/components/select-rich/test/lion-select-rich.test.js
+++ b/packages/ui/components/select-rich/test/lion-select-rich.test.js
@@ -424,6 +424,39 @@ describe('lion-select-rich', () => {
expect(el.singleOption).to.be.false;
expect(_invokerNode.singleOption).to.be.false;
});
+
+ it('adds/removes the autofocus attribute to/from _listboxNode', async () => {
+ const el = await fixture(html` `);
+ const { _listboxNode } = getSelectRichMembers(el);
+
+ expect(_listboxNode.hasAttribute('autofocus')).to.be.false;
+
+ el.opened = true;
+ await el.updateComplete;
+ expect(_listboxNode.hasAttribute('autofocus')).to.be.true;
+
+ el.opened = false;
+ await el.updateComplete;
+ await el.updateComplete; // safari takes a little longer
+ expect(_listboxNode.hasAttribute('autofocus')).to.be.false;
+ });
+
+ it('adds focus to element with [role=listbox] when trapsKeyboardFocus is true', async () => {
+ const el = await fixture(
+ html` `,
+ );
+ const { _listboxNode } = getSelectRichMembers(el);
+ expect(document.activeElement).to.not.equal(_listboxNode);
+
+ el.opened = true;
+ await el.updateComplete;
+ expect(document.activeElement).to.equal(_listboxNode);
+
+ el.opened = false;
+ await el.updateComplete;
+ await el.updateComplete; // safari takes a little longer
+ expect(document.activeElement).to.not.equal(_listboxNode);
+ });
});
describe('interaction-mode', () => {