Fixed keyboard navigation

Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
Charles de Dreuille
2026-03-16 14:51:49 +00:00
parent b0a6ee2a8a
commit 2f581de6ba
10 changed files with 29 additions and 19 deletions
@@ -0,0 +1,7 @@
---
'@backstage/ui': patch
---
Fixed focus ring styles to use React Aria's `[data-focus-visible]` data attribute instead of the native CSS `:focus-visible` pseudo-class. This ensures keyboard focus rings render reliably when focus is managed programmatically by React Aria (e.g. inside a GridList, Menu, or Select).
**Affected components:** Accordion, Button, ButtonIcon, ButtonLink, Card, List, Menu, Select, ToggleButtonGroup
@@ -53,7 +53,7 @@
cursor: pointer;
text-align: left;
&:focus-visible {
&[data-focus-visible] {
outline: none;
transition: none;
box-shadow: inset 0 0 0 2px var(--bui-ring);
@@ -73,7 +73,7 @@
--fg: var(--bui-fg-solid-disabled);
}
&:focus-visible {
&[data-focus-visible] {
outline: 2px solid var(--bui-ring);
outline-offset: 2px;
}
@@ -106,7 +106,7 @@
--bg-active: var(--bg-solid-danger-disabled);
}
&:focus-visible {
&[data-focus-visible] {
outline: 2px solid var(--bui-border-danger);
outline-offset: 2px;
}
@@ -143,7 +143,7 @@
--fg: var(--bui-fg-disabled);
}
&:focus-visible {
&[data-focus-visible] {
outline: none;
transition: none;
box-shadow: inset 0 0 0 2px var(--bui-ring);
@@ -172,7 +172,7 @@
--fg: var(--bui-fg-disabled);
}
&:focus-visible {
&[data-focus-visible] {
box-shadow: inset 0 0 0 2px var(--bui-border-danger);
}
}
@@ -204,7 +204,7 @@
--fg: var(--bui-fg-disabled);
}
&:focus-visible {
&[data-focus-visible] {
outline: none;
transition: none;
box-shadow: inset 0 0 0 2px var(--bui-ring);
@@ -232,7 +232,7 @@
--fg: var(--bui-fg-disabled);
}
&:focus-visible {
&[data-focus-visible] {
box-shadow: inset 0 0 0 2px var(--bui-border-danger);
}
}
@@ -73,7 +73,7 @@
--fg: var(--bui-fg-solid-disabled);
}
&:focus-visible {
&[data-focus-visible] {
outline: 2px solid var(--bui-ring);
outline-offset: 2px;
}
@@ -110,7 +110,7 @@
--fg: var(--bui-fg-disabled);
}
&:focus-visible {
&[data-focus-visible] {
outline: none;
transition: none;
box-shadow: inset 0 0 0 2px var(--bui-ring);
@@ -144,7 +144,7 @@
--fg: var(--bui-fg-disabled);
}
&:focus-visible {
&[data-focus-visible] {
outline: none;
transition: none;
box-shadow: inset 0 0 0 2px var(--bui-ring);
@@ -67,7 +67,7 @@
--fg: var(--bui-fg-solid-disabled);
}
&:focus-visible {
&[data-focus-visible] {
outline: 2px solid var(--bui-ring);
outline-offset: 2px;
}
@@ -103,7 +103,7 @@
--fg: var(--bui-fg-disabled);
}
&:focus-visible {
&[data-focus-visible] {
outline: none;
transition: none;
box-shadow: inset 0 0 0 2px var(--bui-ring);
@@ -136,7 +136,7 @@
--fg: var(--bui-fg-disabled);
}
&:focus-visible {
&[data-focus-visible] {
outline: none;
transition: none;
box-shadow: inset 0 0 0 2px var(--bui-ring);
@@ -69,7 +69,7 @@
}
}
.bui-Card[data-interactive]:has(.bui-CardTrigger:focus-visible) {
.bui-Card[data-interactive]:has(.bui-CardTrigger[data-focus-visible]) {
outline: 2px solid var(--bui-ring);
outline-offset: -2px;
}
@@ -19,7 +19,6 @@
@layer components {
.bui-List {
box-sizing: border-box;
overflow-y: auto;
outline: none;
display: flex;
flex-direction: column;
@@ -30,7 +29,7 @@
gap: 0;
}
&:focus-visible {
&[data-focus-visible] {
outline: none;
}
}
@@ -51,6 +50,10 @@
color: var(--bui-fg-disabled);
}
&[data-focus-visible] {
outline: 2px solid var(--bui-ring);
}
&[data-selection-mode] {
cursor: pointer;
padding-block: var(--bui-space-2);
@@ -78,7 +78,7 @@
padding-inline: var(--bui-space-1);
display: block;
&:focus-visible {
&[data-focus-visible] {
outline: none;
}
@@ -135,7 +135,7 @@
padding-block: var(--bui-space-1);
padding-inline: var(--bui-space-1);
&:focus-visible {
&[data-focus-visible] {
/* Remove default focus-visible outline because React Aria
* triggers it on mouse click open of the list for some reason.
* On keyboard use, the top item receives the focus style,
@@ -102,7 +102,7 @@
}
/* Focus ring on group surface */
.bui-ToggleButtonGroup:focus-visible {
.bui-ToggleButtonGroup[data-focus-visible] {
outline: 2px solid var(--bui-ring);
outline-offset: 2px;
}