Improve cancellation of events when using disabled or aria-disabled attributes (#2890)

* only cancel certain events when disabled

The initial idea was that whenever an element had the `disabled` or
`aria-disabled` prop/attribute that we were going to remove all the
event listeners.

However, this is not ideal because in some scenario's we were actually
explicitly adding `onClick()` listeners (for `<a>` elements) to
`e.preventDefault()` when the link was marked as "disabled" to prevent
it executing the actual link click.

This commit will allow all defined listeners as-is, however, if you are
using one of the following event listeners:

- `onClick`
- `onPointerUp`
- `onPointerDown`
- `onMouseUp`
- `onMouseDown`
- `onKeyUp`
- `onKeyPress`
- `onKeyDown`

Then we will replace it with `(e) => e.preventDefault()` instead.

This way we are still invoking your own listeners, but are explicitly
calling `e.preventDefault()` on listeners that should not be executed in
the first place when an element is `disabled`.

* update CHANGELOG.md

* update CHANGELOG.md
This commit is contained in:
Robin Malfait
2023-12-21 00:09:08 +01:00
committed by GitHub
parent 7a1940e0b2
commit 33a5893e4f
2 changed files with 9 additions and 10 deletions
+2 -1
View File
@@ -9,7 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Allow horizontal scrolling when scroll locking ([bdf4f8e](https://github.com/tailwindlabs/headlessui/commit/bdf4f8e32358485dd9c437c0d631309250ee5624))
- Allow horizontal scrolling inside the `Dialog` component ([#2889](https://github.com/tailwindlabs/headlessui/pull/2889))
- Improve cancellation of events when using `disabled` or `aria-disabled` attributes ([#2890](https://github.com/tailwindlabs/headlessui/pull/2890))
## [2.0.0-alpha.1] - 2023-12-20
@@ -318,16 +318,14 @@ function mergePropsAdvanced(...listOfProps: Props<any, any>[]) {
}
}
// Do not attach any event handlers when there is a `disabled` or `aria-disabled` prop set.
// Ensure event listeners are not called if `disabled` or `aria-disabled` is true
if (target.disabled || target['aria-disabled']) {
return Object.assign(
target,
// Set all event listeners that we collected to `undefined`. This is
// important because of the `cloneElement` from above, which merges the
// existing and new props, they don't just override therefore we have to
// explicitly nullify them.
Object.fromEntries(Object.keys(eventHandlers).map((eventName) => [eventName, undefined]))
)
for (let eventName in eventHandlers) {
// Prevent default events for `onClick`, `onMouseDown`, `onKeyDown`, etc.
if (/^(on(?:Click|Pointer|Mouse|Key)(?:Down|Up|Press)?)$/.test(eventName)) {
eventHandlers[eventName] = [(e: any) => e?.preventDefault?.()]
}
}
}
// Merge event handlers