Description
Is your feature request related to a problem? Please describe.
I cannot augment third-party components with actions because components in Svelte do not have an implicit host/root element at runtime. The most simple example I can think of is a button component from a library that does not support tooltips, but I would like to add a tooltip to the button.
<script>
import MatButton from "svelte-material";
import myTooltip from "../actions/tooltip";
</script>
<!-- Obviously, tooltips are not as relevant for text buttons but I am simplifying the example -->
<MatButton use:myTooltip={"Click me!"}>
Login
</MatButton>
The above code does not compile because there is no host element at runtime for the MatButton
so there is no target for the action. Thus, the MatButton
component must support a tooltip
property or I'm out of luck.
Describe the solution you'd like
I would like components to be able to optionally designate an element in their markup as the root/host element so that actions used on instances of the component get forwarded to that element. In my example, MatButton.svelte
might look something like this:
<script>
// (omitted)
</script>
<!-- Notice this button is marked as the host -->
<button svelte:host>
<slot/>
<div class="ripple"></div>
</button>
Because the MatButton
component gets replaced by a single button
element, I think it is very intuitive for users of the library to think of the MatButton
and the button
element it gets replaced by as one and the same.
At first, I thought the smartest solution would be to automatically allow actions on a component provided its markup has exactly one root element. However, I realized there might be situations where a component has multiple root elements but only one is visible at runtime and is the 'primary' element while the others are there for intercepting focus or some other shenanigans, etc. Besides, it's probably better for component authors to be explicit about whether or not their component maps to a specific runtime element. Thus, I arrived at the svelte:host
marker attribute.
Describe alternatives you've considered
-
Implicitly creating a runtime host element for every component at runtime and injecting components' markup into their host elements. Just kidding! I think Svelte's approach where it replaces component instances with the component markup is vastly superior to Angular and the other frameworks. It gives the developer more control over what the DOM structure looks like at runtime—which means better performance and fewer CSS headaches, and also allows the developer to create very powerful recursive components. Fun Fact: Angular ended up having to work around this madness via attribute components (like
<button mat-button>
instead of<mat-button>
) so that the resulting DOM could be less convoluted and more semantic. -
For my simple tooltip example, I could create a
TooltipHitbox
component with a<slot/>
inside a<div use:myTooltip={tooltipProp}>
and then wrapMatButton
instances with that component. This would create unnecessary wrapper elements at runtime, potentially causing issues with styling, and is also needlessly verbose and obnoxious.
How important is this feature to you?
This feature is not a dealbreaker for me as I feel it is the only bad tradeoff to Svelte's replace-with-markup approach for components. That said, it does make third-party components less extensible because you cannot use actions on them and you cannot forward stuff to their internal markup within your own templates. This means you either have to use a jank workaround (see my first alternative solution) or you end up writing your own version of a library component just because you need to apply an action to the rendered element.