mirror of
https://github.com/supabase/supabase.git
synced 2026-09-06 09:59:03 +08:00
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Bug fix. Two `DropdownMenuTrigger`s wrap a `Button` without `asChild`, so each renders a `<button>` inside a `<button>`. One of them also loses its `aria-label`, leaving an icon-only menu trigger with no accessible name. ## What is the current behavior? `DropdownMenuTrigger` forwards to `DropdownMenuPrimitive.Trigger`, which renders its own `<button>` unless `asChild` is set. So this: ```tsx <DropdownMenuTrigger> <Button variant="default" className="px-1" icon={<MoreVertical />} aria-label={`Open actions for ${hook.title}`} /> </DropdownMenuTrigger> ``` produces `<button><button/></button>`, which is invalid HTML, and puts the props on the inner element rather than on the thing that actually opens the menu. Measured by rendering `HookCard` before and after, rather than reasoning about it: | | before | after | | --- | --- | --- | | `container.querySelectorAll('button button').length` | 1 | 0 | | `aria-label` on `[aria-haspopup="menu"]` | `null` | `Open actions for Send Email` | That second row is the part worth caring about. The `aria-label` was written deliberately for a button whose only content is a `MoreVertical` icon, and it lands on the nested inner button instead of the trigger, so a screen reader gets no name for the control it actually operates. Two sites: - `components/interfaces/Auth/Hooks/HookCard.tsx`, the per-hook actions menu. This is the one with the orphaned `aria-label`. - `components/layouts/ProjectLayout/PauseFailedState.tsx`, the overflow menu next to "Download backup". ## What is the new behavior? Both get `asChild`, so the `Button` becomes the trigger. No nesting, and the props land where they were meant to. ## Additional context #48948 fixed exactly this in `RestoreFailedState.tsx`, which sits in the same directory as `PauseFailedState.tsx` and has the same overflow-menu shape. This is that fix applied to the two places it was not. I swept all 4398 `.tsx` files across studio, www, docs, design-system, ui-library, `packages/ui` and `packages/ui-patterns` for any Radix-style trigger (`DropdownMenu`, `Tooltip`, `Popover`, `Dialog`, `Sheet`, `AlertDialog`, `HoverCard`, `Collapsible`, `ContextMenu`, `Menubar`, `Select`, `Tabs`, `Accordion`) that wraps a button-like element without `asChild`. After discarding one false positive in `EdgeFunctionDetails.tsx`, where the `Button` is a sibling of `TabsTrigger` inside `TabsList` rather than its child, these two are the only ones left. So this should be the end of the pattern rather than the start of a series. No test added, matching what #48948 did for the same change. The `asChild` behaviour belongs to Radix, and a test asserting DOM nesting around two JSX attributes would be testing the library. I did verify it the other way round while developing: a throwaway render assertion failed on unmodified master with a nested-button count of 1 and a null trigger `aria-label`, and passed after the change. Happy to commit that assertion if you would rather have it in the suite. Gates: `test:prettier` passes repo wide, `typecheck --filter=studio --force` passes 9/9, `--filter studio run lint:ratchet` reports rules improved, and the tests covering both touched directories pass (18 files, 143 tests, including the `RestoringState` suite that came in with #48948). Freshman contributor. Found this with Claude Code's help by checking whether the `asChild` fix in #48948 had siblings, and I confirmed the nesting and the missing accessible name myself before touching anything. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved dropdown menu trigger behavior in the authentication hooks and project layout interfaces. * Existing buttons now correctly serve as menu triggers without changing available actions or menu behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai -->