Reputation: 178
I'm using Svelte 3 with the option to generate Custom Elements with Shadow DOM but I can't figure out how to get a reference to the wrapper Custom Element (HTMLElement) so that I can attached event handlers and manipulate attributes. I have something like this:
<svelte:options tag="custom-button"/>
<script>
import { onMount } from 'svelte';
function _onClick(e) {
this.setAttribute('pressed', null);
}
var _boundClick = _onClick.bind(this);
onMount((e) => {
this.addEventListener('click', _boundClick);
return () => {
this.removeEventListener('click', _boundClick);
};
});
</script>
<style>
:host {
display: block;
}
/* Other Styling */
</style>
<slot></slot>
The "this" bits don't work (they do in a normal vanilla Custom Element). Is there some Svelte specific way of getting a reference to the host element in a script?
Thanks
Upvotes: 1
Views: 3227
Reputation: 381
There is a good solution for this now, in the issue thread that Rich Harris linked to above.
You can use customElement's "extend" option to accomplish this:
<svelte:options
customElement={{
tag: 'custom-element',
extend: (customElementConstructor) => {
return class extends customElementConstructor {
constructor() {
super();
this.host = this; // or this.shadowRoot, or whatever you need
}
};
}
}}
/>
<script>
export let host;
</script>
Copied from this comment by "dummdidumm": https://github.com/sveltejs/svelte/issues/3091#issuecomment-1642351615
Upvotes: 0
Reputation: 1
One possible solution is to use the get_current_component function of svelte/internal
import { get_current_component } from 'svelte/internal';
let host = get_current_component();
I think that exporting this function would be very useful.
Upvotes: 0
Reputation: 29615
At present this isn't possible directly, though it would be a worthwhile addition. I've just raised an issue.
The indirect approach would be to do bind:this={element}
on the top-level element inside your custom element (assuming you have one), then you could do something long the lines of $: host = element && element.parentNode.host
. You wouldn't have access to it upon initialisation, but it would be ready in onMount
.
Upvotes: 8
Reputation: 21
I think you want to create an element that surrounds the slot, and then bind that to a variable using bind:this={var}
as is shown in this example: https://svelte.dev/docs#Binding_a_DOM_node
so something like
<custom-button bind:this={customButton}>
<slot></slot>
</custom-button>
Then use that bound variable(customButton
) that in the javascript, instead of this
like so:
let customButton;
function _onClick(e) {
customButton.setAttribute('pressed', null);
}
And so on
Upvotes: 1