diff --git a/CHANGELOG.md b/CHANGELOG.md index a78eabf786..7d8b955eb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## Fixed - [#3690](https://github.com/plotly/dash/pull/3690) Fixes Input when min or max is set to None - [#3723](https://github.com/plotly/dash/pull/3723) Fix misaligned `dcc.Slider` marks when some labels are empty strings +- [#3740](https://github.com/plotly/dash/pull/3740) Fix cannot tab into dropdowns in Safari ## [4.1.0] - 2026-03-23 diff --git a/components/dash-core-components/src/components/css/dropdown.css b/components/dash-core-components/src/components/css/dropdown.css index 5667b85060..6a74a79df0 100644 --- a/components/dash-core-components/src/components/css/dropdown.css +++ b/components/dash-core-components/src/components/css/dropdown.css @@ -55,6 +55,12 @@ cursor: not-allowed; } +.dash-dropdown-focus-target { + position: absolute; + opacity: 0; + pointer-events: none; +} + .dash-dropdown-value { max-width: 100%; text-align: left; diff --git a/components/dash-core-components/src/fragments/Dropdown.tsx b/components/dash-core-components/src/fragments/Dropdown.tsx index 6a838fb1df..cc3f1f230c 100644 --- a/components/dash-core-components/src/fragments/Dropdown.tsx +++ b/components/dash-core-components/src/fragments/Dropdown.tsx @@ -313,6 +313,7 @@ const Dropdown = (props: DropdownProps) => { const relevantKeys = [ 'ArrowDown', 'ArrowUp', + 'Tab', 'PageDown', 'PageUp', 'Home', @@ -342,6 +343,19 @@ const Dropdown = (props: DropdownProps) => { let nextIndex: number; switch (e.key) { + case 'Tab': { + // Trap Tab inside the popover so Safari (which + // skips non-text inputs) can navigate options. + const next = current + (e.shiftKey ? -1 : 1); + if (next < minIndex) { + nextIndex = maxIndex; + } else if (next > maxIndex) { + nextIndex = minIndex; + } else { + nextIndex = next; + } + break; + } case 'ArrowDown': nextIndex = current < maxIndex ? current + 1 : minIndex; break; @@ -408,12 +422,37 @@ const Dropdown = (props: DropdownProps) => { const popover = ( + {/* Safari skips