On using DOM-incompatible elements in slottable components (like triggers) #822
Replies: 2 comments
-
Hi @DaniGuardiola 👋 It sounds like you need the controlled API from our primitives perhaps? Some psuedocode: const [open, setOpen] = React.useState(false);
<DropdownMenu.Root
open={open}
onOpenChange={() => {
if (!open) setOpen(false);
}}
>
<DropdownMenu.Trigger
as={ReactAriaButton}
onPressStart={() => setOpen(true)}
>
Open
</DropdownMenu.Trigger>
<DropdownMenu.Content>{/* ... */}</DropdownMenu.Content>
</DropdownMenu.Root> I've never tried One thing I would say though, separately, is that not all of our triggers fire from a |
Beta Was this translation helpful? Give feedback.
-
Hi, I'm having the same question as OP 😞 . I was wondering if anyone has figured out a clean solution for the interoperability issue. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi Radix team! We're using Radix extensively in our design system at guide.co, and we're combining it with react-aria because we love both and think they are very complimentary. For example, we really like how they have improved the button interactions, and we try to use their hooks for all interactions (press, hover, focus, etc).
For example, we've built a dropdown menu using the Radix primitive, but then the trigger, which is a button, uses the
useButton
hook fromreact-aria
.This presents a big problem, though: from what I've read from the codebase, Radix expects to be able to pass DOM props directly, as if it was a
<button>
component, butreact-aria
abstracts the pointer events into its own API (press events likeonPress
,onPressStart
, etc). This means that when Radix passes a handler toonMouseDown
oronPointerDown
, the component will simply ignore it.I've been able to get around this by wrapping the button component passed to the trigger into an "interceptor" component, which passes the
onPointerDown
to thereact-aria
onPressStart
handler. I also had to add theevent.button = 0
property to the event object because Radix uses it to check if the event is being initiated by the left button of the mouse, but thereact-aria
PressEvent
object doesn't have such property (I believe press events only fire on left click anyway).This is pretty hacky, and very prone to breaking on dep upgrades. I was wondering if you have any recommendations on how to make these two libraries interoperable. One idea I had after reading the code was that if there was an additional layer of abstraction between the slotabble component and the passed element, it could make things easier for these cases. Let me clarify what I mean in pseudocode:
Instead of doing:
It could be done like this:
This would retain the standard API, but would make use-cases like ours easier, because then we can import
TriggerBase
instead ofTrigger
, and do this:Which is a much cleaner approach than the crazy patching we're having to do, and would also prevent unintended breakages. In fact, I'm not sure if it was shipped yet but I noticed that the dropdown menu trigger changed from passing a handler to
onMouseDown
to passing it toonPointerDown
, and that would break if I wasn't being extra careful with dep bumps.One additional ask would be if it'd be possible to make these things type-safe. I know you're working on simplifying the polymorphism stuff by just replacing it altogether with slots, and I love it! It might be a chance to make it type-safe, although I know the typescript support around React children is flaky, but maybe it could be enough with an importable
DropdownMenuTriggerProps
type that I can assign to the passed component so I'm sure I'm not missing anything. In fact, this has been a headache because typescript didn't complain once even though the types were actually completely wrong.Thoughts? Thanks for taking your time reading this! <3
Beta Was this translation helpful? Give feedback.
All reactions