kutty
kutty copied to clipboard
Trigger JS components from outside Alpine
Hi, I would like to trigger a JS component like dropdown or dialog from "outside" the component, in particular from an event handler of an element which is not handled by the component itself. This would mean not using the trigger button allowing normally to open the dialog as shown in the examples.
The specific use case is that I'm using an external library (http://tabulator.info/) that generates some "action buttons" in a cell of the table, and I would like to trigger the opening of the dialog when clicking on that action button.
What I would like to do (pseudo-code imitating a React-like UI lib):
<button on:click={(event) => {
dialogElement.sendToAlpine("open") // or something like that!
}>
<div ref={dialogElement} x-data="dialog()">
// There is no trigger button here
<div class="dialog" x-spread="dialog" x-cloak>
<div class="dialog-content">
...
</div>
</div>
</div>
Is it possible as-is, or by adapting the Alpine components of dialog/dropdown/etc? Or should I rewrite the JS components using Svelte/Vue/React?
I dived into the JavaScript code (e.g. dialog.js
) and tried to hack around with Svelte, here is what I did on Svelte REPL.
This works but is in my sense a bit "overkill" and has remaining questions/problems:
- that's strange to have to put the trigger button inside the dialog
- how to close the dialog from a Svelte event handler?
- the
dialogAction
function feels quite hacky - overall it does not solve the use case explained above: I still have to render the trigger button as a child of
<div x-spread="trigger">
, otherwise the Alpine component won't see it
Afterthought: would it be possible to break the Alpine JS components into base functions that could still be called by the Alpine JS components, but could be also be called by Svelte/Vue/React components?
Anyway, thanks for the excellent work and for your reactivity about following Tailwind v2 release!
I know what you are saying, it's annoying for me too to build the dialog component in the same place as the trigger. But I don't think there is a way to separate those for now. I'll ask some alpine people about how to make it better.
Also checkout headlessui which will I'm thinking of using once it's released.
I'll keep this issue open until we find a solution.
There's a couple of ways to interact with Alpine components from outside of them.
The cleanest is to send custom events (dispatchEvent(new CustomEvent('my-event'))
) and listen to that event on the Alpine side.
You can also find the root DOM node and read/write the Alpine.js state at .__x.$data
For reference, here's a good article on how to trigger custom events from outside: https://tonylea.com/setting-alpine-data-outside-of-the-component