Summary
When a DropdownMenu (or MoreMenu) is opened with a mouse click, focus moves to the first enabled item and its focus ring renders. To users it reads as "this item is already selected" — several people on my team have asked whether the first action was pre-chosen or somehow highlighted by mistake.
For keyboard opens this is exactly right and shouldn't change. The problem is only that pointer opens get the same treatment, and there's no prop to opt out.
What I ran into
A table row actions menu — Edit details / Edit permissions / Delete role:
<DropdownMenu
button={{ label: `Actions for ${role.name}`, icon: <MoreVertical />, isIconOnly: true, variant: 'ghost' }}
hasChevron={false}
>
<DropdownMenuItem icon={Pencil} label="Edit details" onClick={...} />
<DropdownMenuItem icon={SlidersHorizontal} label="Edit permissions" onClick={...} />
<DropdownMenuItem icon={<Trash2 />} label={<span>Delete role</span>} onClick={...} />
</DropdownMenu>
Click the three-dot trigger → "Edit details" is visibly highlighted before the pointer goes anywhere near it. It also shifts depending on state: when the first item is isDisabled, the highlight lands on whichever item is first enabled, so the "selected" row appears to move around between rows in the same table.
Same behavior via the items data prop and via MoreMenu, so it looks like it's in the shared keyboard/focus path rather than either wrapper.
Why it's awkward to work around
DropdownMenuProps exposes button, isMenuOpen, onOpenChange, menuWidth, onClick, hasChevron, placement, data-testid — nothing focus-related. DropdownMenuItemProps has icon, label, description, onClick, isDisabled, endContent. So there's no supported way to say "don't focus anything until the user arrows in", short of CSS against internals, which I'd rather not ship.
Proposals (either would solve it)
A. Match focus behavior to the input modality (my preference — no new API, fixes it everywhere at once)
Focus the first item when the menu is opened via keyboard (Enter / Space / ArrowDown on the trigger), but on pointer open leave focus on the menu container so nothing is visually highlighted. First ArrowDown then moves to item 1. This is what most menu implementations do, and it pairs naturally with :focus-visible.
B. Add an opt-out prop
<DropdownMenu hasInitialFocus={false}> ... </DropdownMenu>
Defaults to true so nothing changes for existing users.
If the highlight is intended to be :focus-visible-driven already, then this may just be a bug where the ring shows on programmatic focus after a pointer open.
Acceptance criteria
Summary
When a
DropdownMenu(orMoreMenu) is opened with a mouse click, focus moves to the first enabled item and its focus ring renders. To users it reads as "this item is already selected" — several people on my team have asked whether the first action was pre-chosen or somehow highlighted by mistake.For keyboard opens this is exactly right and shouldn't change. The problem is only that pointer opens get the same treatment, and there's no prop to opt out.
What I ran into
A table row actions menu — Edit details / Edit permissions / Delete role:
Click the three-dot trigger → "Edit details" is visibly highlighted before the pointer goes anywhere near it. It also shifts depending on state: when the first item is
isDisabled, the highlight lands on whichever item is first enabled, so the "selected" row appears to move around between rows in the same table.Same behavior via the
itemsdata prop and viaMoreMenu, so it looks like it's in the shared keyboard/focus path rather than either wrapper.Why it's awkward to work around
DropdownMenuPropsexposesbutton,isMenuOpen,onOpenChange,menuWidth,onClick,hasChevron,placement,data-testid— nothing focus-related.DropdownMenuItemPropshasicon,label,description,onClick,isDisabled,endContent. So there's no supported way to say "don't focus anything until the user arrows in", short of CSS against internals, which I'd rather not ship.Proposals (either would solve it)
A. Match focus behavior to the input modality (my preference — no new API, fixes it everywhere at once)
Focus the first item when the menu is opened via keyboard (
Enter/Space/ArrowDownon the trigger), but on pointer open leave focus on the menu container so nothing is visually highlighted. FirstArrowDownthen moves to item 1. This is what most menu implementations do, and it pairs naturally with:focus-visible.B. Add an opt-out prop
Defaults to
trueso nothing changes for existing users.If the highlight is intended to be
:focus-visible-driven already, then this may just be a bug where the ring shows on programmatic focus after a pointer open.Acceptance criteria
ArrowDownmoves to the first item.DropdownMenuitems-array mode,DropdownMenucompound mode, andMoreMenu.