Skip to content

Commit 46a9b32

Browse files
thecrypticaceRobinMalfait
authored andcommitted
Don’t override explicit disabled prop for components inside <MenuItem> (#2929)
* Don’t override explicit disabled prop inside `<MenuItem>` * Update changelog
1 parent 39210df commit 46a9b32

File tree

4 files changed

+90
-4
lines changed

4 files changed

+90
-4
lines changed

packages/@headlessui-react/src/components/menu/menu.test.tsx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,47 @@ describe('Rendering', () => {
421421
assertMenu({ state: MenuState.InvisibleUnmounted })
422422
})
423423
)
424+
425+
it('should not override an explicit disabled prop on MenuItems child', async () => {
426+
render(
427+
<Menu>
428+
<Menu.Button>Trigger</Menu.Button>
429+
<Menu.Items>
430+
<Menu.Item>{({ disabled }) => <button disabled={disabled}>Item A</button>}</Menu.Item>
431+
<Menu.Item>{({ disabled }) => <button disabled={disabled}>Item B</button>}</Menu.Item>
432+
<Menu.Item disabled>
433+
{({ disabled }) => <button disabled={disabled}>Item C</button>}
434+
</Menu.Item>
435+
</Menu.Items>
436+
</Menu>
437+
)
438+
439+
assertMenuButton({
440+
state: MenuState.InvisibleUnmounted,
441+
})
442+
assertMenu({ state: MenuState.InvisibleUnmounted })
443+
444+
getMenuButton()?.focus()
445+
446+
await press(Keys.Enter)
447+
448+
assertMenuButton({
449+
state: MenuState.Visible,
450+
})
451+
assertMenu({ state: MenuState.Visible })
452+
assertMenuItem(getMenuItems()[0], {
453+
tag: 'button',
454+
attributes: {},
455+
})
456+
assertMenuItem(getMenuItems()[1], {
457+
tag: 'button',
458+
attributes: {},
459+
})
460+
assertMenuItem(getMenuItems()[2], {
461+
tag: 'button',
462+
attributes: { disabled: '' },
463+
})
464+
})
424465
})
425466

426467
it('should guarantee the order of DOM nodes when performing actions', async () => {

packages/@headlessui-vue/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Expose `disabled` state on `<Tab />` component ([#2918](https://github.com/tailwindlabs/headlessui/pull/2918))
1313
- Prevent default behaviour when clicking outside of a `DialogPanel` ([#2919](https://github.com/tailwindlabs/headlessui/pull/2919))
14+
- Don’t override explicit `disabled` prop for components inside `<MenuItem>` ([#2929](https://github.com/tailwindlabs/headlessui/pull/2929))
1415

1516
## [1.7.19] - 2024-02-07
1617

packages/@headlessui-vue/src/components/menu/menu.test.tsx

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,53 @@ describe('Rendering', () => {
686686
})
687687
})
688688

689+
it('should not override an explicit disabled prop on MenuItems child', async () => {
690+
renderTemplate(jsx`
691+
<Menu>
692+
<MenuButton>Trigger</MenuButton>
693+
<MenuItems>
694+
<MenuItem v-slot="{ active, disabled }">
695+
<button :data-active="active" :disabled="disabled">Item A</button>
696+
</MenuItem>
697+
<MenuItem v-slot="{ active, disabled }">
698+
<button :data-active="active" :disabled="disabled">Item B</button>
699+
</MenuItem>
700+
<MenuItem disabled v-slot="{ active, disabled }">
701+
<button :data-active="active" :disabled="disabled">Item C</button>
702+
</MenuItem>
703+
</MenuItems>
704+
</Menu>
705+
`)
706+
707+
assertMenuButton({
708+
state: MenuState.InvisibleUnmounted,
709+
attributes: { id: 'headlessui-menu-button-1' },
710+
})
711+
assertMenu({ state: MenuState.InvisibleUnmounted })
712+
713+
getMenuButton()?.focus()
714+
715+
await press(Keys.Enter)
716+
717+
assertMenuButton({
718+
state: MenuState.Visible,
719+
attributes: { id: 'headlessui-menu-button-1' },
720+
})
721+
assertMenu({ state: MenuState.Visible })
722+
assertMenuItem(getMenuItems()[0], {
723+
tag: 'button',
724+
attributes: { 'data-active': 'true' },
725+
})
726+
assertMenuItem(getMenuItems()[1], {
727+
tag: 'button',
728+
attributes: { 'data-active': 'false' },
729+
})
730+
assertMenuItem(getMenuItems()[2], {
731+
tag: 'button',
732+
attributes: { 'data-active': 'false', disabled: '' },
733+
})
734+
})
735+
689736
it('should yell when we render a MenuItem using a template `as` prop that contains multiple children', async () => {
690737
expect.hasAssertions()
691738

@@ -712,7 +759,6 @@ describe('Rendering', () => {
712759
'The current component <MenuItem /> is rendering a "template".',
713760
'However we need to passthrough the following props:',
714761
' - aria-disabled',
715-
' - disabled',
716762
' - id',
717763
' - onClick',
718764
' - onFocus',

packages/@headlessui-vue/src/components/menu/menu.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -566,16 +566,14 @@ export let MenuItem = defineComponent({
566566
}
567567

568568
return () => {
569-
let { disabled } = props
569+
let { disabled, ...theirProps } = props
570570
let slot = { active: active.value, disabled, close: api.closeMenu }
571-
let { ...theirProps } = props
572571
let ourProps = {
573572
id,
574573
ref: internalItemRef,
575574
role: 'menuitem',
576575
tabIndex: disabled === true ? undefined : -1,
577576
'aria-disabled': disabled === true ? true : undefined,
578-
disabled: undefined, // Never forward the `disabled` prop
579577
onClick: handleClick,
580578
onFocus: handleFocus,
581579
onPointerenter: handleEnter,

0 commit comments

Comments
 (0)