diff --git a/.changeset/fifty-coins-enjoy.md b/.changeset/fifty-coins-enjoy.md new file mode 100644 index 00000000000..6bc622bf8a7 --- /dev/null +++ b/.changeset/fifty-coins-enjoy.md @@ -0,0 +1,7 @@ +--- +'@primer/react': patch +--- + +When passing an `id` prop to ActionMenu.Button, it will be passed as the rendered button element's `id` attribute instead of being set as an automatically generated ID. + + diff --git a/src/ActionMenu/ActionMenu.tsx b/src/ActionMenu/ActionMenu.tsx index 724532ada11..d579694cd3f 100644 --- a/src/ActionMenu/ActionMenu.tsx +++ b/src/ActionMenu/ActionMenu.tsx @@ -46,8 +46,13 @@ const Menu: React.FC> = ({ const onOpen = React.useCallback(() => setCombinedOpenState(true), [setCombinedOpenState]) const onClose = React.useCallback(() => setCombinedOpenState(false), [setCombinedOpenState]) + const menuButtonChild = React.Children.toArray(children).find( + child => React.isValidElement(child) && (child.type === MenuButton || child.type === Anchor), + ) + const menuButtonChildId = React.isValidElement(menuButtonChild) ? menuButtonChild.props.id : undefined + const anchorRef = useProvidedRefOrCreate(externalAnchorRef) - const anchorId = useId() + const anchorId = useId(menuButtonChildId) let renderAnchor: AnchoredOverlayProps['renderAnchor'] = null // 🚨 Hack for good API! // we strip out Anchor from children and pass it to AnchoredOverlay to render diff --git a/src/__tests__/ActionMenu.test.tsx b/src/__tests__/ActionMenu.test.tsx index aa9d4024b07..4631773e114 100644 --- a/src/__tests__/ActionMenu.test.tsx +++ b/src/__tests__/ActionMenu.test.tsx @@ -364,4 +364,36 @@ describe('ActionMenu', () => { button.focus() expect(component.getByRole('tooltip')).toBeInTheDocument() }) + + it('should pass the "id" prop from ActionMenu.Button to the HTML button', async () => { + const buttonId = 'toggle-menu-custom-id' + const component = HTMLRender( + + + + + Toggle Menu + + + New file + + Copy link + Edit file + event.preventDefault()}> + Delete file + + + Github + + + + + + + , + ) + const button = component.getByRole('button') + + expect(button.id).toBe(buttonId) + }) })