Skip to content

Commit 3cdd953

Browse files
fix: avoid triggering onClick on disabled links (#8828)
* fix: avoid triggering onClick on disabled links * add link specific test and fix event order * remove unneeded code --------- Co-authored-by: Robert Snow <[email protected]> Co-authored-by: Robert Snow <[email protected]>
1 parent 661ba8e commit 3cdd953

File tree

3 files changed

+30
-4
lines changed

3 files changed

+30
-4
lines changed

packages/@react-aria/interactions/src/usePress.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,10 +298,18 @@ export function usePress(props: PressHookProps): PressResult {
298298
});
299299

300300
let triggerClick = useEffectEvent((e: RMouseEvent<FocusableElement>) => {
301+
if (isDisabled) {
302+
return;
303+
}
304+
301305
onClick?.(e);
302306
});
303307

304308
let triggerSyntheticClick = useEffectEvent((e: KeyboardEvent | TouchEvent, target: FocusableElement) => {
309+
if (isDisabled) {
310+
return;
311+
}
312+
305313
// Some third-party libraries pass in onClick instead of onPress.
306314
// Create a fake mouse event and trigger onClick as well.
307315
// This matches the browser's native activation behavior for certain elements (e.g. button).
@@ -374,7 +382,7 @@ export function usePress(props: PressHookProps): PressResult {
374382
if (isDisabled) {
375383
e.preventDefault();
376384
}
377-
385+
378386
// If triggered from a screen reader or by using element.click(),
379387
// trigger as if it were a keyboard click.
380388
if (!state.ignoreEmulatedMouseEvents && !state.isPressed && (state.pointerType === 'virtual' || isVirtualClick(e.nativeEvent))) {

packages/@react-aria/interactions/test/usePress.test.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,7 +1049,7 @@ describe('usePress', function () {
10491049
]);
10501050
});
10511051

1052-
it('should not fire press events for disabled elements', function () {
1052+
it('should not fire press/click events for disabled elements', function () {
10531053
let events = [];
10541054
let addEvent = (e) => events.push(e);
10551055
let res = render(
@@ -1066,6 +1066,7 @@ describe('usePress', function () {
10661066
let el = res.getByText('test');
10671067
fireEvent(el, pointerEvent('pointerdown', {pointerId: 1, pointerType: 'mouse'}));
10681068
fireEvent(el, pointerEvent('pointerup', {pointerId: 1, pointerType: 'mouse', clientX: 0, clientY: 0}));
1069+
fireEvent.click(el);
10691070

10701071
expect(events).toEqual([]);
10711072
});
@@ -4553,12 +4554,13 @@ describe('usePress', function () {
45534554
]);
45544555
});
45554556

4556-
it('should not fire press events for disabled elements', function () {
4557-
const shadowRoot = setupShadowDOMTest({isDisabled: true});
4557+
it('should not fire press/click events for disabled elements', function () {
4558+
const shadowRoot = setupShadowDOMTest({isDisabled: true, onClick: e => addEvent({type: e.type, target: e.target})});
45584559

45594560
const el = shadowRoot.getElementById('testElement');
45604561
fireEvent(el, pointerEvent('pointerdown', {pointerId: 1, pointerType: 'mouse'}));
45614562
fireEvent(el, pointerEvent('pointerup', {pointerId: 1, pointerType: 'mouse', clientX: 0, clientY: 0}));
4563+
fireEvent.click(el);
45624564

45634565
expect(events).toEqual([]);
45644566
});

packages/react-aria-components/test/Link.test.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,20 @@ describe('Link', () => {
149149
await user.click(link);
150150
expect(navigate).toHaveBeenCalledWith('/foo', {foo: 'bar'});
151151
});
152+
153+
it('should not navigate if disabled', async () => {
154+
let navigate = jest.fn();
155+
let useHref = href => '/base' + href;
156+
let onClick = jest.fn();
157+
let {getByRole} = render(
158+
<RouterProvider navigate={navigate} useHref={useHref}>
159+
<Link isDisabled href="/foo" routerOptions={{foo: 'bar'}} onClick={onClick}>Test</Link>
160+
</RouterProvider>
161+
);
162+
let link = getByRole('link');
163+
expect(link).toHaveAttribute('href', '/base/foo');
164+
await user.click(link);
165+
expect(navigate).not.toHaveBeenCalled();
166+
expect(onClick).not.toHaveBeenCalled();
167+
});
152168
});

0 commit comments

Comments
 (0)