diff --git a/packages/components/src/components/dropdown-select/dropdown-select.spec.ts b/packages/components/src/components/dropdown-select/dropdown-select.spec.ts
index 201b20318e..7aa1bd97da 100644
--- a/packages/components/src/components/dropdown-select/dropdown-select.spec.ts
+++ b/packages/components/src/components/dropdown-select/dropdown-select.spec.ts
@@ -123,4 +123,65 @@ describe('DropdownSelect', function () {
expect(changeSpy).not.toBeCalled();
});
});
+
+ describe('focus outline (issue #2428)', () => {
+ it('should NOT have steal-focus part when a non-first item is initially selected and dropdown is closed', async () => {
+ const page = await newSpecPage({
+ components: [DropdownSelect],
+ html: `
+
+ Caspar
+ Cedric
+ Cem
+ `,
+ });
+
+ const selectEl = page.doc.querySelector('scale-dropdown-select');
+ const baseEl = selectEl.shadowRoot.querySelector(
+ '[part~="select"]'
+ ) as HTMLElement;
+
+ // The part attribute must NOT contain "steal-focus" while dropdown is closed,
+ // regardless of which item is initially selected.
+ expect(baseEl.getAttribute('part')).not.toContain('steal-focus');
+ });
+
+ it('should NOT have steal-focus part when the last item is initially selected and dropdown is closed', async () => {
+ const page = await newSpecPage({
+ components: [DropdownSelect],
+ html: `
+
+ Caspar
+ Cedric
+ Cem
+ `,
+ });
+
+ const selectEl = page.doc.querySelector('scale-dropdown-select');
+ const baseEl = selectEl.shadowRoot.querySelector(
+ '[part~="select"]'
+ ) as HTMLElement;
+
+ expect(baseEl.getAttribute('part')).not.toContain('steal-focus');
+ });
+
+ it('should NOT have steal-focus part when first item is initially selected and dropdown is closed', async () => {
+ const page = await newSpecPage({
+ components: [DropdownSelect],
+ html: `
+
+ Caspar
+ Cedric
+ Cem
+ `,
+ });
+
+ const selectEl = page.doc.querySelector('scale-dropdown-select');
+ const baseEl = selectEl.shadowRoot.querySelector(
+ '[part~="select"]'
+ ) as HTMLElement;
+
+ expect(baseEl.getAttribute('part')).not.toContain('steal-focus');
+ });
+ });
});
diff --git a/packages/components/src/components/dropdown-select/dropdown-select.tsx b/packages/components/src/components/dropdown-select/dropdown-select.tsx
index 463b79c411..8e5285cf92 100644
--- a/packages/components/src/components/dropdown-select/dropdown-select.tsx
+++ b/packages/components/src/components/dropdown-select/dropdown-select.tsx
@@ -279,17 +279,24 @@ export class DropdownSelect {
@Watch('value')
valueChange(newValue) {
- this.currentIndex = readOptions(this.hostElement).findIndex(
- ({ value }) => value === newValue
- );
+ // Do not set currentIndex while the dropdown is closed. Doing so would add
+ // the `steal-focus` CSS part and suppress the focus outline.
+ // However, when the dropdown is already open, controlled/programmatic value
+ // updates must keep currentIndex in sync so the highlighted option and
+ // aria-activedescendant stay aligned with the selected value.
+ if (this.open && Array.isArray(this.options)) {
+ this.currentIndex = this.options.findIndex(
+ (option) => option.value === newValue
+ );
+ }
+
this.updateInputHidden(newValue);
}
connectedCallback() {
- this.currentIndex =
- readOptions(this.hostElement).findIndex(
- ({ value }) => value === this.value
- ) || -1;
+ // currentIndex intentionally starts at -1 (the @State() default).
+ // The dropdown is closed on init, so steal-focus must not be applied.
+ // currentIndex is set to the selected item's index when the dropdown opens.
}
componentDidRender() {
@@ -376,6 +383,12 @@ export class DropdownSelect {
this.comboEl.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
this.comboEl.focus();
this.currentIndex = -1;
+ } else {
+ // Initialize currentIndex to the currently selected item so that keyboard
+ // navigation starts from the right position and the item is highlighted.
+ this.currentIndex = readOptions(this.hostElement).findIndex(
+ ({ value }) => value === this.value
+ );
}
}
diff --git a/packages/visual-tests/setup.js b/packages/visual-tests/setup.js
index 997ca763c9..a9cb337136 100644
--- a/packages/visual-tests/setup.js
+++ b/packages/visual-tests/setup.js
@@ -22,7 +22,16 @@ module.exports = async (jestConfig) => {
res.sendFile('index.html');
});
- global.__SERVER__ = app.listen(3123);
+ await new Promise((resolve, reject) => {
+ const server = app.listen(3123, '0.0.0.0', () => {
+ console.log(
+ '\nScale Visual Tests: Storybook server listening on 0.0.0.0:3123'
+ );
+ resolve();
+ });
+ server.on('error', reject);
+ global.__SERVER__ = server;
+ });
await setupPuppeteer(jestConfig);
};
diff --git a/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-disabled-1-snap.png b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-disabled-1-snap.png
new file mode 100644
index 0000000000..bc47410eaa
Binary files /dev/null and b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-disabled-1-snap.png differ
diff --git a/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-disabled-2-snap.png b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-disabled-2-snap.png
new file mode 100644
index 0000000000..bc47410eaa
Binary files /dev/null and b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-disabled-2-snap.png differ
diff --git a/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-error-1-snap.png b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-error-1-snap.png
new file mode 100644
index 0000000000..579ef253a9
Binary files /dev/null and b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-error-1-snap.png differ
diff --git a/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-error-2-snap.png b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-error-2-snap.png
new file mode 100644
index 0000000000..ed314ade3e
Binary files /dev/null and b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-error-2-snap.png differ
diff --git a/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-standard-1-snap.png b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-standard-1-snap.png
new file mode 100644
index 0000000000..504185ab82
Binary files /dev/null and b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-standard-1-snap.png differ
diff --git a/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-standard-2-snap.png b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-standard-2-snap.png
new file mode 100644
index 0000000000..28ff4d1abf
Binary files /dev/null and b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-standard-2-snap.png differ
diff --git a/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-standard-3-snap.png b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-standard-3-snap.png
new file mode 100644
index 0000000000..ad67a39761
Binary files /dev/null and b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-standard-3-snap.png differ
diff --git a/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-standard-4-snap.png b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-standard-4-snap.png
new file mode 100644
index 0000000000..200e9421de
Binary files /dev/null and b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-dark-standard-4-snap.png differ
diff --git a/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-disabled-1-snap.png b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-disabled-1-snap.png
new file mode 100644
index 0000000000..3e713c34e7
Binary files /dev/null and b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-disabled-1-snap.png differ
diff --git a/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-disabled-2-snap.png b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-disabled-2-snap.png
new file mode 100644
index 0000000000..3e713c34e7
Binary files /dev/null and b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-disabled-2-snap.png differ
diff --git a/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-error-1-snap.png b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-error-1-snap.png
new file mode 100644
index 0000000000..300b29419b
Binary files /dev/null and b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-error-1-snap.png differ
diff --git a/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-error-2-snap.png b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-error-2-snap.png
new file mode 100644
index 0000000000..125a34d2ce
Binary files /dev/null and b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-error-2-snap.png differ
diff --git a/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-standard-1-snap.png b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-standard-1-snap.png
new file mode 100644
index 0000000000..5a859df5aa
Binary files /dev/null and b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-standard-1-snap.png differ
diff --git a/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-standard-2-snap.png b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-standard-2-snap.png
new file mode 100644
index 0000000000..12eb4e044c
Binary files /dev/null and b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-standard-2-snap.png differ
diff --git a/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-standard-3-snap.png b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-standard-3-snap.png
new file mode 100644
index 0000000000..593d236e96
Binary files /dev/null and b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-standard-3-snap.png differ
diff --git a/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-standard-4-snap.png b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-standard-4-snap.png
new file mode 100644
index 0000000000..9b4d0ab265
Binary files /dev/null and b/packages/visual-tests/src/__image_snapshots__/dropdown-select-visual-spec-js-dropdown-select-light-standard-4-snap.png differ
diff --git a/packages/visual-tests/src/dropdown-select.visual.spec.js b/packages/visual-tests/src/dropdown-select.visual.spec.js
index 55e8cbe586..be1ececdaa 100644
--- a/packages/visual-tests/src/dropdown-select.visual.spec.js
+++ b/packages/visual-tests/src/dropdown-select.visual.spec.js
@@ -1,4 +1,4 @@
-describe.skip('DropdownSelect', () => {
+describe('DropdownSelect', () => {
describe.each(['light', 'dark'])('%p', (mode) => {
beforeAll(async () => {
await global.runColorSetup('components-dropdown-select--standard', mode);