You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
FUI is an amazing library that is very simple to use. However, using it inside a Svelte component library is not simple at all. Why? Because it works with HTML elements, which are hidden by Svelte (and to be fair, others too). Let's take a look at an example: A button component that wants to show a tooltip.
We start by examining FUI's requirement for placement: We need the HTML element reference of the button, and the HTML reference of the DIV that makes up the tooltip. The latter requires the position to be set equal to the strategy (absolute or fixed). Trivial stuff because the natural place to place the FUI code is inside the Tooltip component. I'll place code that uses Bootstrap.
Let us not concern ourselves about the JS part. Not important. Just note the bind:this={tooltipEl}. We need a similar reference from the button. However, the button element is enclosed inside the Button component:
Since Svelte does not have the feature I'm asking for, I have to willingly expose a reference of the button HTML element so the Tooltip component can receive it. Now imagine having to do this on every component in the library.
Describe the proposed solution
It would be great if Svelte provided a built-in mechanism that automagically exported the root/first HTML element reference so one could pick it up by binding to a prop. It would be great if I could just do:
<Button bind:rootref={buttonEl} ... >
I have a tooltip!
</Button>
<Tooltip referenceEl={buttonEl} ... >
I am the tooltip for the button.
</Tooltip>
The automatic rootref property would be a reference to the first element in the component's markup, and yes, it would have to be smart enough to sort the IF blocks that may be on top, making rootref change reactively to changes in the markup.
To complete the feature, the developer could use syntax to mark the element that is desired as the "root reference". You guys are the experts, but I imagine something like:
<button><spanrootbind>...</span><button>
A simple keyword that I apply to the one element I want, but that can be applied in different IF branches. The rule would be: After deciding on the HTML elements that will be visible, there must be among them at least zero, and at most one element marked with rootbind.
Finally, in order to not pollute RAM with a bunch of references that aren't in use, this could only get activated for component instances that have the bind:rootref binding.
Alternatives considered
Reference Prop on Every Component
The most obvious one is to export a reference to the root HTML element of every component in the library. This pollutes RAM as only a few will be really needed.
Slots
I have also considered using slots. This one is quite interesting but note that it also has the same RAM issue as every component instance spends a variable to hold on to a ref that may or may not be used.
<ButtonfuiTriggerOpts={{hideTriggers:Triggers.All,showTriggers:Triggers.All}}><svelte:fragmentslot="content">
Focus or hover me!
</svelte:fragment><Tooltipshadow={true}slot="floatUi" placement="top-end" let:referencereferenceEl={reference}><divclass="fancy-tooltip"><divclass="big"><Iconname="keyboard" /> + <Iconname="mouse-solid" /></div><p>I appear or disappear on <strong>keyboard focus</strong> or <strong>mouse hover</strong> events.</p></div></Tooltip></Button>
This is my attempt with slots. The floatUi slot provides a reference slot variable that holds the reference to the <button> element. This technique is kind of nice, but it has problems:
There can only be one floating user interface element per "parent" component. What if I wanted a tooltip AND a menu on click? I cannot since there's only one slot for floating UI.
Every Button component in the entire application will be creating the HTML element reference, wasting RAM in most cases as it is only needed when pairing with a floating UI piece.
Every component in the component library would need to be extended with this kind of setup (a content slot and a floating slot) so they too can have floating UI's associated with them.
Context
This is an idea I haven't tested: Every component that could be used as the reference element of a FUI would expose its "root element" reference as context with setContext(). Then, FUI components like Tooltip can then use getContext() to obtain the reference and do the FUI calculations for position with it.
Again, waste of RAM here. There will be a LOT of contexts everywhere that won't be in use.
Importance
would make my life easier
The text was updated successfully, but these errors were encountered:
webJose
changed the title
Feature to easily access the HTML element reference of the root/first/<user defined> of a component to ease the use of certain JS libraries
Feature to easily access the reference of the root/first/<user defined> HTML element of a component to ease the use of certain JS libraries
Oct 7, 2023
Describe the problem
I'll expose the problem using Floating-UI (FUI).
FUI is an amazing library that is very simple to use. However, using it inside a Svelte component library is not simple at all. Why? Because it works with HTML elements, which are hidden by Svelte (and to be fair, others too). Let's take a look at an example: A button component that wants to show a tooltip.
We start by examining FUI's requirement for placement: We need the HTML element reference of the button, and the HTML reference of the DIV that makes up the tooltip. The latter requires the position to be set equal to the strategy (
absolute
orfixed
). Trivial stuff because the natural place to place the FUI code is inside theTooltip
component. I'll place code that uses Bootstrap.Let us not concern ourselves about the JS part. Not important. Just note the
bind:this={tooltipEl}
. We need a similar reference from the button. However, the button element is enclosed inside the Button component:Since Svelte does not have the feature I'm asking for, I have to willingly expose a reference of the button HTML element so the Tooltip component can receive it. Now imagine having to do this on every component in the library.
Describe the proposed solution
It would be great if Svelte provided a built-in mechanism that automagically exported the root/first HTML element reference so one could pick it up by binding to a prop. It would be great if I could just do:
The automatic
rootref
property would be a reference to the first element in the component's markup, and yes, it would have to be smart enough to sort the IF blocks that may be on top, making rootref change reactively to changes in the markup.To complete the feature, the developer could use syntax to mark the element that is desired as the "root reference". You guys are the experts, but I imagine something like:
A simple keyword that I apply to the one element I want, but that can be applied in different IF branches. The rule would be: After deciding on the HTML elements that will be visible, there must be among them at least zero, and at most one element marked with
rootbind
.Finally, in order to not pollute RAM with a bunch of references that aren't in use, this could only get activated for component instances that have the
bind:rootref
binding.Alternatives considered
Reference Prop on Every Component
The most obvious one is to export a reference to the root HTML element of every component in the library. This pollutes RAM as only a few will be really needed.
Slots
I have also considered using slots. This one is quite interesting but note that it also has the same RAM issue as every component instance spends a variable to hold on to a ref that may or may not be used.
This is my attempt with slots. The
floatUi
slot provides areference
slot variable that holds the reference to the<button>
element. This technique is kind of nice, but it has problems:Context
This is an idea I haven't tested: Every component that could be used as the reference element of a FUI would expose its "root element" reference as context with
setContext()
. Then, FUI components likeTooltip
can then usegetContext()
to obtain the reference and do the FUI calculations for position with it.Again, waste of RAM here. There will be a LOT of contexts everywhere that won't be in use.
Importance
would make my life easier
The text was updated successfully, but these errors were encountered: