Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/clean-mugs-sing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@salt-ds/core": patch
---

Fixed intermittent appearance of `MenuItem` focus ring during mouse hover
4 changes: 2 additions & 2 deletions packages/core/src/__tests__/__e2e__/menu/Menu.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,10 @@ describe("Given a Menu", () => {
cy.get("@alertStub").should("not.have.been.called");
});

it("should focus items on hover", () => {
it("should not focus items on hover", () => {
cy.mount(<SingleLevel open />);
cy.findByRole("menuitem", { name: "Paste" }).realHover();
cy.findByRole("menuitem", { name: "Paste" }).should("have.focus");
cy.findByRole("menuitem", { name: "Paste" }).should("not.have.focus");
});

it("should support open being uncontrolled", () => {
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/menu/MenuBase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ export function MenuBase(props: MenuBaseProps) {
activeIndex,
nested: isNested,
onNavigate: setActiveIndex,
focusItemOnHover: false,
}),
],
);
Expand Down
30 changes: 17 additions & 13 deletions packages/core/src/menu/MenuItem.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,34 @@
outline-offset: calc(var(--salt-size-fixed-100) * -2);
}

.saltMenuItem:hover {
outline: none;
}

.saltMenuItem:hover,
.saltMenuItem:focus-visible {
background: var(--salt-selectable-background-hover);
}

.saltMenuItem:active {
.saltMenuItem:active,
.saltMenuItem-blurActive:not(:hover) {
background: var(--salt-selectable-background-selected);
box-shadow:
0 calc(var(--salt-size-fixed-100) * -1) 0 0 var(--salt-selectable-borderColor-selected),
0 var(--salt-size-fixed-100) 0 0 var(--salt-selectable-borderColor-selected);
}

.saltMenuItem-blurActive:not(:hover) {
z-index: var(--salt-zIndex-default);
/* Transitions prevent visual flicker when rapidly moving mouse between menu items */
transition:
box-shadow 50ms ease-in-out,
background 50ms ease-in-out;
}

.saltMenuItem-blurActive:hover {
box-shadow: none;
transition:
box-shadow var(--salt-duration-instant),
background var(--salt-duration-instant);
}

.saltMenuItem[aria-disabled="true"],
.saltMenuItem[aria-disabled="true"]:active {
background: var(--salt-selectable-background-disabled);
Expand All @@ -45,14 +57,6 @@
box-shadow: none;
}

.saltMenuItem-blurActive {
z-index: var(--salt-zIndex-default);
background: var(--salt-selectable-background-selected);
box-shadow:
0 calc(var(--salt-size-fixed-100) * -1) 0 0 var(--salt-selectable-borderColor-selected),
0 var(--salt-size-fixed-100) 0 0 var(--salt-selectable-borderColor-selected);
}

/* TODO: Find a better way of doing this */
.saltMenuItem .saltIcon:not(.saltCheckboxIcon-icon) {
min-height: var(--salt-text-lineHeight);
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/menu/MenuTrigger.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const MenuTrigger = forwardRef<HTMLElement, MenuTriggerProps>(

return (
<MenuTriggerContext.Provider
value={{ triggersSubmenu: true, blurActive: focusInside && openState }}
Copy link
Contributor

@mark-tate mark-tate Oct 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On this one... you may have a warning as focusInside is pulled from useMenuContext but no longer used, after this deletion.

value={{ triggersSubmenu: true, blurActive: openState }}
>
{cloneElement(children, {
...mergeProps(
Expand Down
Loading