Skip to content

feat: Support onClick as an alias for onPress #7891

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Mar 28, 2025
Merged

Conversation

devongovett
Copy link
Member

@devongovett devongovett commented Mar 7, 2025

Proposal for discussion. See this discussion: https://x.com/deebovv/status/1897355956188537016

In particular:

For us (@UntitledUI) it was the unfamiliarity of the community with the “onPress” prop and the “onClick” prop being deprecated in React Aria buttons. Therefore we had to map the onClick to onPress internally for buttons. I wish it “just worked” without people having to relearn what they have been doing for years (I think bun is a great example).

The problem is that onPress makes it harder to integrate with other libraries.

For example, a 3rd party popover library might pass down onClick to the trigger. But if the trigger is React Aria button we have to remap onClick to onPress.

Or the opposite, cannot use a native button as a trigger with React Aria popover because it uses onPress and we have to remap it again.

We solved the second case with <Pressable> added in the last release. The first case of using a RAC Button as a trigger for a third-party component that passes in onClick remains.

This PR basically treats onClick as an alias for onPress. It gets fired at the same times. If we have a native MouseEvent event available, it gets passed to the handler. If not, e.g. in a keyboard event, we synthesize a fake click event and pass that. This matches what browsers do for certain elements: https://html.spec.whatwg.org/#fire-a-synthetic-pointer-event.

Questions:

  • We do some event filtering in usePress to avoid edge cases. For example, we only fire onPress for left clicks, not right clicks, and we don't fire onPress for repeating keyboard events. Seems like matching this in onClick would be good to take advantage of this behavior, but could be unexpected that it doesn't match the browser behavior for onClick. But if people will be using onClick just because they're used to that name, they'd lose out on some of this improved behavior, so I lean towards having it match onPress. Thoughts?
  • Also, is it unexpected to fire onClick in cases where the browser doesn't do so?
  • I marked onClick as @deprecated in the prop definition, which means it'll be omitted from the docs. This way we nudge people toward onPress but it works regardless, e.g. when used with third party libraries. Also means it'll be rendered with a strikethrough in people's IDEs. But, there's no more console warning. Thoughts?

@rspbot
Copy link

rspbot commented Mar 7, 2025

@deebov
Copy link
Contributor

deebov commented Mar 7, 2025

Thanks for opening up this discussion @devongovett. I would like to first inform myself better with the issues usePress tackles before making a thoughtful suggestion.

How much of the issues you described in (Building a Button Part 1: Press Events) is still relevant? It's been 5 years since the article was published — I assume browsers had at least fixed some of the inconsistencies mentioned in the article. Or are there as well other sources to check which issues usePress solves?

@devongovett
Copy link
Member Author

Some of it is still relevant, but there have been quite a few improvements. I'm planning on writing an update to that blog post series soon.

The major thing that changed recently is that buttons now receive focus consistently in all browsers, so this part is no longer necessary. Therefore, as of #7542 we no longer use preventDefault in usePress. That PR lists a whole bunch of issues that were fixed.

Also in that PR, we now trigger onPress during the native onClick event instead of onPointerUp, which fixed some additional issues. The old browser fallbacks for mouse/touch events are also no longer necessary since all browsers support pointer events (unfortunately JSDOM does not, which prevents us from removing it entirely). The custom hit testing described there is also no longer needed. At this point, onPress is only fired during onClick and onKeyUp. onPressStart and onPressEnd are fired during pointer events.

However, other behaviors described in the original blog post, such as text selection behavior, active state, hover state, cancelation, virtual clicks, repeating keyboard events, etc. still apply. I believe it's still important to handle those for a good experience, especially on mobile/touch devices, but luckily we can now rely on native events more.

@MilllerTime
Copy link

MilllerTime commented Mar 8, 2025

Looking good @devongovett!

We do some event filtering in usePress to avoid edge cases. For example, we only fire onPress for left clicks, not right clicks, and we don't fire onPress for repeating keyboard events. Seems like matching this in onClick would be good to take advantage of this behavior, but could be unexpected that it doesn't match the browser behavior for onClick. But if people will be using onClick just because they're used to that name, they'd lose out on some of this improved behavior, so I lean towards having it match onPress. Thoughts?

I think your onPress implementation makes a lot of sense for common UI components – onClick would benefit from that work too, and it may not be that much different from native behavior. In your example of filtering only left clicks, browsers do this too, right? I don't trust my memory, so quickly tested this with a mouse on both a <button> and <div> in Chrome and FF (Safari isn't handy atm). "click" events only fired on a left click for each.

Also, is it unexpected to fire onClick in cases where the browser doesn't do so?

What are the cases? Anything beyond keyboard events?

I marked onClick as @deprecated in the prop definition, which means it'll be omitted from the docs. This way we nudge people toward onPress but it works regardless, e.g. when used with third party libraries. Also means it'll be rendered with a strikethrough in people's IDEs. But, there's no more console warning. Thoughts?

If I saw a strikethrough, but it worked, though I couldn't find info in the docs, I'd be a little confused. Would it be okay to treat onClick as a sort of "compatibility alias", not a deprecated feature, and the docs explain this while recommending onPress when possible?

@alexasselin008
Copy link
Contributor

Hi Devon,

We're building our company's design system on top of React Aria Components, and I’m really interested in this discussion. I’ve been exploring the idea of aliasing onClick everywhere onPress is used, since most of the developers I work with primarily interact with our wrapper around RAC rather than React Aria Components directly.

Regarding your questions, I think it makes the most sense for onClick to align with onPress behavior. The primary use case for onClick in this context seems to be as an alias rather than exposing the native browser onClick. If consumers need to bypass the improvements you made to onPress, they can always attach an event handler via a ref.

As for event filtering and triggering onClick where the browser normally wouldn't, that approach seems reasonable as it aligns with RAC’s goal of optimizing UX.

Lastly, about the @deprecated tag in the prop definition, if onClick is truly equivalent to onPress, marking it as deprecated seems to introduce unnecessary friction. An alternative like @alias or simply leaving it undocumented would make using this alias (and the library) smoother for consumers.

In any cases, thank you for considering this API change, and more importantly thank you for your work on RAC

@devongovett
Copy link
Member Author

@MilllerTime

In your example of filtering only left clicks, browsers do this too, right?

You're right. onClick is only fired for left clicks. I was thinking of onMouseDown and onMouseUp. The repeating keyboard events (hold down the enter key) are a case where browsers fire repeated clicks and we do not fire repeated onPress events.

What are the cases? Anything beyond keyboard events?

Keyboard events are the main one. Another case is iOS which does not fire onClick if you press and hold, unlike other browsers. We normalize this case so that onPress is always fired.

@MilllerTime
Copy link

Thanks for clarifying @devongovett. This all sounds like a desirable upgrade. It's almost like a compatibility fix for onClick, which makes a lot of sense to expose under the same name in a UI kit. Appreciate the pragmatism in offering it!

@deebov
Copy link
Contributor

deebov commented Mar 17, 2025

If I saw a strikethrough, but it worked, though I couldn't find info in the docs, I'd be a little confused. Would it be okay to treat onClick as a sort of "compatibility alias", not a deprecated feature, and the docs explain this while recommending onPress when possible?

This all sounds like a desirable upgrade.

I pretty much agree with what @MilllerTime has stated. So onClick would "just work" as people (not browsers) expect but with some small consistency improvements borrowed from onPress.

…onclick

# Conflicts:
#	packages/@react-aria/interactions/src/utils.ts
@devongovett
Copy link
Member Author

Thanks all for the feedback! We're going to move ahead with this. I've removed @deprecated and added additional info to the prop description.

@devongovett devongovett marked this pull request as ready for review March 21, 2025 00:12
snowystinger
snowystinger previously approved these changes Mar 21, 2025
LFDanLu
LFDanLu previously approved these changes Mar 21, 2025
Copy link
Member

@LFDanLu LFDanLu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@devongovett devongovett dismissed stale reviews from LFDanLu and snowystinger via fcce3ac March 22, 2025 01:17
@rspbot
Copy link

rspbot commented Mar 22, 2025

@rspbot
Copy link

rspbot commented Mar 22, 2025

@rspbot
Copy link

rspbot commented Mar 22, 2025

## API Changes

react-aria-components

/react-aria-components:Button

 Button {
   aria-controls?: string
   aria-current?: boolean | 'true' | 'false' | 'page' | 'step' | 'location' | 'date' | 'time'
   aria-describedby?: string
   aria-details?: string
   aria-expanded?: boolean | 'true' | 'false'
   aria-haspopup?: boolean | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog' | 'true' | 'false'
   aria-label?: string
   aria-labelledby?: string
   aria-pressed?: boolean | 'true' | 'false' | 'mixed'
   autoFocus?: boolean
   children?: ReactNode | ((ButtonRenderProps & {
     defaultChildren: ReactNode | undefined
 })) => ReactNode
   className?: string | ((ButtonRenderProps & {
     defaultClassName: string | undefined
 })) => string
   excludeFromTabOrder?: boolean
   form?: string
   formAction?: string
   formEncType?: string
   formMethod?: string
   formNoValidate?: boolean
   formTarget?: string
   id?: string
   isDisabled?: boolean
   isPending?: boolean
   name?: string
   onBlur?: (FocusEvent<Target>) => void
+  onClick?: (MouseEvent<FocusableElement>) => void
   onFocus?: (FocusEvent<Target>) => void
   onFocusChange?: (boolean) => void
   onHoverChange?: (boolean) => void
   onHoverEnd?: (HoverEvent) => void
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPress?: (PressEvent) => void
   onPressChange?: (boolean) => void
   onPressEnd?: (PressEvent) => void
   onPressStart?: (PressEvent) => void
   onPressUp?: (PressEvent) => void
   preventFocusOnPress?: boolean
   slot?: string | null
   style?: CSSProperties | ((ButtonRenderProps & {
     defaultStyle: CSSProperties
 })) => CSSProperties | undefined
   type?: 'button' | 'submit' | 'reset' = 'button'
   value?: string
 }

/react-aria-components:Link

 Link {
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   autoFocus?: boolean
   children?: ReactNode | ((LinkRenderProps & {
     defaultChildren: ReactNode | undefined
 })) => ReactNode
   className?: string | ((LinkRenderProps & {
     defaultClassName: string | undefined
 })) => string
   download?: boolean | string
   href?: Href
   hrefLang?: string
   isDisabled?: boolean
   onBlur?: (FocusEvent<Target>) => void
+  onClick?: (MouseEvent<FocusableElement>) => void
   onFocus?: (FocusEvent<Target>) => void
   onFocusChange?: (boolean) => void
   onHoverChange?: (boolean) => void
   onHoverEnd?: (HoverEvent) => void
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPress?: (PressEvent) => void
   onPressChange?: (boolean) => void
   onPressEnd?: (PressEvent) => void
   onPressStart?: (PressEvent) => void
   onPressUp?: (PressEvent) => void
   ping?: string
   referrerPolicy?: HTMLAttributeReferrerPolicy
   rel?: string
   routerOptions?: RouterOptions
   slot?: string | null
   style?: CSSProperties | ((LinkRenderProps & {
     defaultStyle: CSSProperties
 })) => CSSProperties | undefined
   target?: HTMLAttributeAnchorTarget
 }

/react-aria-components:ToggleButton

 ToggleButton {
   aria-controls?: string
   aria-describedby?: string
   aria-details?: string
   aria-expanded?: boolean | 'true' | 'false'
   aria-haspopup?: boolean | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog' | 'true' | 'false'
   aria-label?: string
   aria-labelledby?: string
   aria-pressed?: boolean | 'true' | 'false' | 'mixed'
   autoFocus?: boolean
   children?: ReactNode | ((ToggleButtonRenderProps & {
     defaultChildren: ReactNode | undefined
 })) => ReactNode
   className?: string | ((ToggleButtonRenderProps & {
     defaultClassName: string | undefined
 })) => string
   defaultSelected?: boolean
   excludeFromTabOrder?: boolean
   id?: Key
   isDisabled?: boolean
   isSelected?: boolean
   onBlur?: (FocusEvent<Target>) => void
   onChange?: (boolean) => void
+  onClick?: (MouseEvent<FocusableElement>) => void
   onFocus?: (FocusEvent<Target>) => void
   onFocusChange?: (boolean) => void
   onHoverChange?: (boolean) => void
   onHoverEnd?: (HoverEvent) => void
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPress?: (PressEvent) => void
   onPressChange?: (boolean) => void
   onPressEnd?: (PressEvent) => void
   onPressStart?: (PressEvent) => void
   onPressUp?: (PressEvent) => void
   preventFocusOnPress?: boolean
   slot?: string | null
   style?: CSSProperties | ((ToggleButtonRenderProps & {
     defaultStyle: CSSProperties
 })) => CSSProperties | undefined
   type?: 'button' | 'submit' | 'reset' = 'button'
 }

/react-aria-components:Pressable

 Pressable {
   allowTextSelectionOnPress?: boolean
   children: ReactElement<DOMAttributes, string>
   isDisabled?: boolean
   isPressed?: boolean
+  onClick?: (MouseEvent<FocusableElement>) => void
   onPress?: (PressEvent) => void
   onPressChange?: (boolean) => void
   onPressEnd?: (PressEvent) => void
   onPressStart?: (PressEvent) => void
   preventFocusOnPress?: boolean
   shouldCancelOnPointerExit?: boolean
 }

/react-aria-components:ButtonProps

 ButtonProps {
   aria-controls?: string
   aria-current?: boolean | 'true' | 'false' | 'page' | 'step' | 'location' | 'date' | 'time'
   aria-describedby?: string
   aria-details?: string
   aria-expanded?: boolean | 'true' | 'false'
   aria-haspopup?: boolean | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog' | 'true' | 'false'
   aria-label?: string
   aria-labelledby?: string
   aria-pressed?: boolean | 'true' | 'false' | 'mixed'
   autoFocus?: boolean
   children?: ReactNode | ((ButtonRenderProps & {
     defaultChildren: ReactNode | undefined
 })) => ReactNode
   className?: string | ((ButtonRenderProps & {
     defaultClassName: string | undefined
 })) => string
   excludeFromTabOrder?: boolean
   form?: string
   formAction?: string
   formEncType?: string
   formMethod?: string
   formNoValidate?: boolean
   formTarget?: string
   id?: string
   isDisabled?: boolean
   isPending?: boolean
   name?: string
   onBlur?: (FocusEvent<Target>) => void
+  onClick?: (MouseEvent<FocusableElement>) => void
   onFocus?: (FocusEvent<Target>) => void
   onFocusChange?: (boolean) => void
   onHoverChange?: (boolean) => void
   onHoverEnd?: (HoverEvent) => void
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPress?: (PressEvent) => void
   onPressChange?: (boolean) => void
   onPressEnd?: (PressEvent) => void
   onPressStart?: (PressEvent) => void
   onPressUp?: (PressEvent) => void
   preventFocusOnPress?: boolean
   slot?: string | null
   style?: CSSProperties | ((ButtonRenderProps & {
     defaultStyle: CSSProperties
 })) => CSSProperties | undefined
   type?: 'button' | 'submit' | 'reset' = 'button'
   value?: string
 }

/react-aria-components:LinkProps

 LinkProps {
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   autoFocus?: boolean
   children?: ReactNode | ((LinkRenderProps & {
     defaultChildren: ReactNode | undefined
 })) => ReactNode
   className?: string | ((LinkRenderProps & {
     defaultClassName: string | undefined
 })) => string
   download?: boolean | string
   href?: Href
   hrefLang?: string
   isDisabled?: boolean
   onBlur?: (FocusEvent<Target>) => void
+  onClick?: (MouseEvent<FocusableElement>) => void
   onFocus?: (FocusEvent<Target>) => void
   onFocusChange?: (boolean) => void
   onHoverChange?: (boolean) => void
   onHoverEnd?: (HoverEvent) => void
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPress?: (PressEvent) => void
   onPressChange?: (boolean) => void
   onPressEnd?: (PressEvent) => void
   onPressStart?: (PressEvent) => void
   onPressUp?: (PressEvent) => void
   ping?: string
   referrerPolicy?: HTMLAttributeReferrerPolicy
   rel?: string
   routerOptions?: RouterOptions
   slot?: string | null
   style?: CSSProperties | ((LinkRenderProps & {
     defaultStyle: CSSProperties
 })) => CSSProperties | undefined
   target?: HTMLAttributeAnchorTarget
 }

/react-aria-components:ToggleButtonProps

 ToggleButtonProps {
   aria-controls?: string
   aria-describedby?: string
   aria-details?: string
   aria-expanded?: boolean | 'true' | 'false'
   aria-haspopup?: boolean | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog' | 'true' | 'false'
   aria-label?: string
   aria-labelledby?: string
   aria-pressed?: boolean | 'true' | 'false' | 'mixed'
   autoFocus?: boolean
   children?: ReactNode | ((ToggleButtonRenderProps & {
     defaultChildren: ReactNode | undefined
 })) => ReactNode
   className?: string | ((ToggleButtonRenderProps & {
     defaultClassName: string | undefined
 })) => string
   defaultSelected?: boolean
   excludeFromTabOrder?: boolean
   id?: Key
   isDisabled?: boolean
   isSelected?: boolean
   onBlur?: (FocusEvent<Target>) => void
   onChange?: (boolean) => void
+  onClick?: (MouseEvent<FocusableElement>) => void
   onFocus?: (FocusEvent<Target>) => void
   onFocusChange?: (boolean) => void
   onHoverChange?: (boolean) => void
   onHoverEnd?: (HoverEvent) => void
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPress?: (PressEvent) => void
   onPressChange?: (boolean) => void
   onPressEnd?: (PressEvent) => void
   onPressStart?: (PressEvent) => void
   onPressUp?: (PressEvent) => void
   preventFocusOnPress?: boolean
   slot?: string | null
   style?: CSSProperties | ((ToggleButtonRenderProps & {
     defaultStyle: CSSProperties
 })) => CSSProperties | undefined
   type?: 'button' | 'submit' | 'reset' = 'button'
 }

@react-aria/breadcrumbs

/@react-aria/breadcrumbs:AriaBreadcrumbItemProps

 AriaBreadcrumbItemProps {
   aria-current?: 'page' | 'step' | 'location' | 'date' | 'time' | boolean | 'true' | 'false' = 'page'
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   autoFocus?: boolean
   children: ReactNode
   download?: boolean | string
   elementType?: string = 'a'
   href?: Href
   hrefLang?: string
   id?: string
   isCurrent?: boolean
   isDisabled?: boolean
   onBlur?: (FocusEvent<Target>) => void
+  onClick?: (MouseEvent<FocusableElement>) => void
   onFocus?: (FocusEvent<Target>) => void
   onFocusChange?: (boolean) => void
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPressChange?: (boolean) => void
   onPressEnd?: (PressEvent) => void
   onPressStart?: (PressEvent) => void
   onPressUp?: (PressEvent) => void
   ping?: string
   referrerPolicy?: HTMLAttributeReferrerPolicy
   rel?: string
   routerOptions?: RouterOptions
   target?: HTMLAttributeAnchorTarget
 }

@react-aria/button

/@react-aria/button:AriaButtonOptions

 AriaButtonOptions <E extends ElementType> {
   aria-controls?: string
   aria-current?: boolean | 'true' | 'false' | 'page' | 'step' | 'location' | 'date' | 'time'
   aria-describedby?: string
   aria-details?: string
   aria-expanded?: boolean | 'true' | 'false'
   aria-haspopup?: boolean | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog' | 'true' | 'false'
   aria-label?: string
   aria-labelledby?: string
   aria-pressed?: boolean | 'true' | 'false' | 'mixed'
   autoFocus?: boolean
   elementType?: ElementType | JSXElementConstructor<any> = 'button'
   excludeFromTabOrder?: boolean
   href?: string
   id?: string
   isDisabled?: boolean
   onBlur?: (FocusEvent<Target>) => void
+  onClick?: (MouseEvent<FocusableElement>) => void
   onFocus?: (FocusEvent<Target>) => void
   onFocusChange?: (boolean) => void
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPressChange?: (boolean) => void
   onPressEnd?: (PressEvent) => void
   onPressStart?: (PressEvent) => void
   onPressUp?: (PressEvent) => void
   preventFocusOnPress?: boolean
   rel?: string
   target?: string
   type?: 'button' | 'submit' | 'reset' = 'button'
 }

/@react-aria/button:AriaButtonProps

 AriaButtonProps <T extends ElementType = 'button'> {
   aria-controls?: string
   aria-current?: boolean | 'true' | 'false' | 'page' | 'step' | 'location' | 'date' | 'time'
   aria-describedby?: string
   aria-details?: string
   aria-expanded?: boolean | 'true' | 'false'
   aria-haspopup?: boolean | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog' | 'true' | 'false'
   aria-label?: string
   aria-labelledby?: string
   aria-pressed?: boolean | 'true' | 'false' | 'mixed'
   autoFocus?: boolean
   children?: ReactNode
   elementType?: ElementType | JSXElementConstructor<any> = 'button'
   excludeFromTabOrder?: boolean
   href?: string
   id?: string
   isDisabled?: boolean
   onBlur?: (FocusEvent<Target>) => void
+  onClick?: (MouseEvent<FocusableElement>) => void
   onFocus?: (FocusEvent<Target>) => void
   onFocusChange?: (boolean) => void
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPressChange?: (boolean) => void
   onPressEnd?: (PressEvent) => void
   onPressStart?: (PressEvent) => void
   onPressUp?: (PressEvent) => void
   preventFocusOnPress?: boolean
   rel?: string
   target?: string
   type?: 'button' | 'submit' | 'reset' = 'button'
 }

/@react-aria/button:AriaToggleButtonProps

 AriaToggleButtonProps <T extends ElementType = 'button'> {
   aria-controls?: string
   aria-describedby?: string
   aria-details?: string
   aria-expanded?: boolean | 'true' | 'false'
   aria-haspopup?: boolean | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog' | 'true' | 'false'
   aria-label?: string
   aria-labelledby?: string
   aria-pressed?: boolean | 'true' | 'false' | 'mixed'
   autoFocus?: boolean
   children?: ReactNode
   defaultSelected?: boolean
   elementType?: ElementType | JSXElementConstructor<any> = 'button'
   excludeFromTabOrder?: boolean
   id?: string
   isDisabled?: boolean
   isSelected?: boolean
   onBlur?: (FocusEvent<Target>) => void
   onChange?: (boolean) => void
+  onClick?: (MouseEvent<FocusableElement>) => void
   onFocus?: (FocusEvent<Target>) => void
   onFocusChange?: (boolean) => void
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPressChange?: (boolean) => void
   onPressEnd?: (PressEvent) => void
   onPressStart?: (PressEvent) => void
   onPressUp?: (PressEvent) => void
   preventFocusOnPress?: boolean
   type?: 'button' | 'submit' | 'reset' = 'button'
 }

/@react-aria/button:AriaToggleButtonGroupItemProps

 AriaToggleButtonGroupItemProps <E extends ElementType = 'button'> {
   aria-controls?: string
   aria-describedby?: string
   aria-details?: string
   aria-expanded?: boolean | 'true' | 'false'
   aria-haspopup?: boolean | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog' | 'true' | 'false'
   aria-label?: string
   aria-labelledby?: string
   aria-pressed?: boolean | 'true' | 'false' | 'mixed'
   autoFocus?: boolean
   children?: ReactNode
   elementType?: ElementType | JSXElementConstructor<any> = 'button'
   excludeFromTabOrder?: boolean
   id: Key
   isDisabled?: boolean
   onBlur?: (FocusEvent<Target>) => void
+  onClick?: (MouseEvent<FocusableElement>) => void
   onFocus?: (FocusEvent<Target>) => void
   onFocusChange?: (boolean) => void
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPressChange?: (boolean) => void
   onPressEnd?: (PressEvent) => void
   onPressStart?: (PressEvent) => void
   onPressUp?: (PressEvent) => void
   preventFocusOnPress?: boolean
   type?: 'button' | 'submit' | 'reset' = 'button'
 }

@react-aria/dnd

/@react-aria/dnd:DropResult

 DropResult {
   dropButtonProps?: AriaButtonProps
-  dropProps: HTMLAttributes<HTMLElement>
+  dropProps: DOMAttributes
   isDropTarget: boolean
 }

@react-aria/interactions

/@react-aria/interactions:Pressable

 Pressable {
   allowTextSelectionOnPress?: boolean
   children: ReactElement<DOMAttributes, string>
   isDisabled?: boolean
   isPressed?: boolean
+  onClick?: (MouseEvent<FocusableElement>) => void
   onPress?: (PressEvent) => void
   onPressChange?: (boolean) => void
   onPressEnd?: (PressEvent) => void
   onPressStart?: (PressEvent) => void
   preventFocusOnPress?: boolean
   shouldCancelOnPointerExit?: boolean
 }

/@react-aria/interactions:PressResponder

 PressResponder {
   allowTextSelectionOnPress?: boolean
   children: ReactNode
   isDisabled?: boolean
   isPressed?: boolean
+  onClick?: (MouseEvent<FocusableElement>) => void
   onPress?: (PressEvent) => void
   onPressChange?: (boolean) => void
   onPressEnd?: (PressEvent) => void
   onPressStart?: (PressEvent) => void
   preventFocusOnPress?: boolean
   shouldCancelOnPointerExit?: boolean
 }

/@react-aria/interactions:PressProps

 PressProps {
   allowTextSelectionOnPress?: boolean
   isDisabled?: boolean
   isPressed?: boolean
+  onClick?: (MouseEvent<FocusableElement>) => void
   onPress?: (PressEvent) => void
   onPressChange?: (boolean) => void
   onPressEnd?: (PressEvent) => void
   onPressStart?: (PressEvent) => void
   preventFocusOnPress?: boolean
   shouldCancelOnPointerExit?: boolean
 }

/@react-aria/interactions:PressHookProps

 PressHookProps {
   allowTextSelectionOnPress?: boolean
   isDisabled?: boolean
   isPressed?: boolean
+  onClick?: (MouseEvent<FocusableElement>) => void
   onPress?: (PressEvent) => void
   onPressChange?: (boolean) => void
   onPressEnd?: (PressEvent) => void
   onPressStart?: (PressEvent) => void
   preventFocusOnPress?: boolean
   ref?: RefObject<Element | null>
   shouldCancelOnPointerExit?: boolean
 }

/@react-aria/interactions:PressEvents

 PressEvents {
+  onClick?: (MouseEvent<FocusableElement>) => void
   onPress?: (PressEvent) => void
   onPressChange?: (boolean) => void
   onPressEnd?: (PressEvent) => void
   onPressStart?: (PressEvent) => void
 }

@react-aria/link

/@react-aria/link:AriaLinkOptions

 AriaLinkOptions {
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   autoFocus?: boolean
   download?: boolean | string
   elementType?: string = 'a'
   href?: Href
   hrefLang?: string
   isDisabled?: boolean
   onBlur?: (FocusEvent<Target>) => void
+  onClick?: (MouseEvent<FocusableElement>) => void
   onFocus?: (FocusEvent<Target>) => void
   onFocusChange?: (boolean) => void
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPressChange?: (boolean) => void
   onPressEnd?: (PressEvent) => void
   onPressStart?: (PressEvent) => void
   onPressUp?: (PressEvent) => void
   ping?: string
   referrerPolicy?: HTMLAttributeReferrerPolicy
   rel?: string
   routerOptions?: RouterOptions
   target?: HTMLAttributeAnchorTarget
 }

@react-aria/menu

/@react-aria/menu:AriaMenuItemProps

 AriaMenuItemProps {
   aria-controls?: string
   aria-expanded?: boolean | 'true' | 'false'
   aria-haspopup?: 'menu' | 'dialog'
   aria-label?: string
   closeOnSelect?: boolean = true
   id?: string
   isVirtualized?: boolean
   key: Key
   onBlur?: (FocusEvent<Target>) => void
+  onClick?: (MouseEvent<FocusableElement>) => void
   onFocus?: (FocusEvent<Target>) => void
   onFocusChange?: (boolean) => void
   onHoverChange?: (boolean) => void
   onHoverEnd?: (HoverEvent) => void
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPress?: (PressEvent) => void
   onPressChange?: (boolean) => void
   onPressEnd?: (PressEvent) => void
   onPressStart?: (PressEvent) => void
   onPressUp?: (PressEvent) => void
   selectionManager?: SelectionManager
 }

@react-spectrum/textfield

/@react-spectrum/textfield:TextFieldBase

 TextFieldBase extends Partial {
   UNSAFE_className?: string
   UNSAFE_style?: CSSProperties
   alignSelf?: Responsive<'auto' | 'normal' | 'start' | 'end' | 'center' | 'flex-start' | 'flex-end' | 'self-start' | 'self-end' | 'stretch'>
   aria-activedescendant?: string
   aria-autocomplete?: 'none' | 'inline' | 'list' | 'both'
   aria-controls?: string
   aria-describedby?: string
   aria-details?: string
   aria-errormessage?: string
   aria-haspopup?: boolean | 'false' | 'true' | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog'
   aria-label?: string
   aria-labelledby?: string
   autoComplete?: string
   autoCorrect?: string
   autoFocus?: boolean
   bottom?: Responsive<DimensionValue>
   contextualHelp?: ReactNode
   defaultValue?: string
   description?: ReactNode
   descriptionProps?: HTMLAttributes<HTMLElement>
   disableFocusRing?: boolean
   end?: Responsive<DimensionValue>
   enterKeyHint?: 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send'
   errorMessage?: ReactNode | (ValidationResult) => ReactNode
   errorMessageProps?: HTMLAttributes<HTMLElement>
   excludeFromTabOrder?: boolean
   flex?: Responsive<string | number | boolean>
   flexBasis?: Responsive<number | string>
   flexGrow?: Responsive<number>
   flexShrink?: Responsive<number>
   gridArea?: Responsive<string>
   gridColumn?: Responsive<string>
   gridColumnEnd?: Responsive<string>
   gridColumnStart?: Responsive<string>
   gridRow?: Responsive<string>
   gridRowEnd?: Responsive<string>
   gridRowStart?: Responsive<string>
   height?: Responsive<DimensionValue>
   icon?: ReactElement | null
   id?: string
   inputClassName?: string
   inputMode?: 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search'
   inputProps: InputHTMLAttributes<HTMLInputElement> | TextareaHTMLAttributes<HTMLTextAreaElement>
   inputRef?: RefObject<HTMLInputElement | HTMLTextAreaElement | null>
   isDisabled?: boolean
   isHidden?: Responsive<boolean>
   isLoading?: boolean
   isQuiet?: boolean
   isReadOnly?: boolean
   isRequired?: boolean
   justifySelf?: Responsive<'auto' | 'normal' | 'start' | 'end' | 'flex-start' | 'flex-end' | 'self-start' | 'self-end' | 'center' | 'left' | 'right' | 'stretch'>
   label?: ReactNode
   labelAlign?: Alignment = 'start'
   labelPosition?: LabelPosition = 'top'
   labelProps?: LabelHTMLAttributes<HTMLLabelElement>
   left?: Responsive<DimensionValue>
   loadingIndicator?: ReactElement
   margin?: Responsive<DimensionValue>
   marginBottom?: Responsive<DimensionValue>
   marginEnd?: Responsive<DimensionValue>
   marginStart?: Responsive<DimensionValue>
   marginTop?: Responsive<DimensionValue>
   marginX?: Responsive<DimensionValue>
   marginY?: Responsive<DimensionValue>
   maxHeight?: Responsive<DimensionValue>
   maxLength?: number
   maxWidth?: Responsive<DimensionValue>
   minHeight?: Responsive<DimensionValue>
   minLength?: number
   minWidth?: Responsive<DimensionValue>
   multiLine?: boolean
   name?: string
   necessityIndicator?: NecessityIndicator = 'icon'
   onBeforeInput?: FormEventHandler<HTMLInputElement>
   onBlur?: (FocusEvent<T>) => void
+  onClick?: (MouseEvent<FocusableElement>) => void
   onCompositionEnd?: CompositionEventHandler<HTMLInputElement>
   onCompositionStart?: CompositionEventHandler<HTMLInputElement>
   onCompositionUpdate?: CompositionEventHandler<HTMLInputElement>
   onCopy?: ClipboardEventHandler<HTMLInputElement>
   onFocus?: (FocusEvent<T>) => void
   onFocusChange?: (boolean) => void
   onInput?: FormEventHandler<HTMLInputElement>
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPaste?: ClipboardEventHandler<HTMLInputElement>
   onPress?: (PressEvent) => void
   onPressChange?: (boolean) => void
   onPressEnd?: (PressEvent) => void
   onPressStart?: (PressEvent) => void
   onPressUp?: (PressEvent) => void
   onSelect?: ReactEventHandler<HTMLInputElement>
   order?: Responsive<number>
   pattern?: string
   position?: Responsive<'static' | 'relative' | 'absolute' | 'fixed' | 'sticky'>
   right?: Responsive<DimensionValue>
   spellCheck?: string
   start?: Responsive<DimensionValue>
   top?: Responsive<DimensionValue>
   type?: 'text' | 'search' | 'url' | 'tel' | 'email' | 'password' | (string & {
   
 })
   validationBehavior?: 'aria' | 'native' = 'aria'
   validationIconClassName?: string
   validationState?: ValidationState
   value?: string
   width?: Responsive<DimensionValue>
   wrapperChildren?: ReactElement | Array<ReactElement>
   zIndex?: Responsive<number>
 }

@devongovett devongovett added this pull request to the merge queue Mar 28, 2025
Merged via the queue into main with commit a45c71c Mar 28, 2025
30 checks passed
@devongovett devongovett deleted the usepress-onclick branch March 28, 2025 20:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants