Description
Describe the bug
With a Svelte custom element, if you export variables and then bind them to attributes on a root <template>
tag, then those attributes are automatically reflected to the host element (i.e. this works):
<svelte:options customElement={{ tag: "my-tab" }} />
<script>
export let role = "tab"
</script>
<template {role}>
<svelte:element this="slot" />
</template>
This results in...
<my-tab role="tab">The "[role='tab']" bit is automatically reflected.</my-tab>
If you try to leverage this binding behavior further in ways that follow conventional Svelte patterns, the consistency ends there.
Reproduction
Judging from the initial binding behavior, I would then expect all of the following to also work with the root <template>
element.
<svelte:options customElement={{ tag: "my-tab", props: {
expanded: { reflect: true, type: 'Boolean' }
}}} />
<script>
export let expanded = false;
function onClick() {
expanded = !expanded;
console.log("my-tab was clicked!");
}
</script>
<template
{expanded}
class:expanded
aria-expanded={expanded ? "true" : undefined}
on:click={() => expanded = !expanded}
on:click={onClick}
>
<svelte:element this="slot" />
</template>
The only one that did work for me was the first feature (the {expanded}
bit):
- No class named "expanded" was added or removed from the
my-tab
element'sclass
attribute in response to state changes. - Attempting to do so with attributes that include dashes, like
aria-expanded
, merely has no effect whatsoever. - Attempting to bind an inline event handler actually resulted in some sort of parse error in my experience. All text after the
=>
just ends becoming part of a text node prepended to the element's shadow DOM (in this case, it would containexpanded = !expanded}>
, including the curly brace and angled bracket). I could only fix it by switching to a direct function reference; however... - Attempting to bind an event handler with a direct function reference never actually triggers the event handler.
As it stands, I am having to fetch a reference to the host element via the new extends
feature and do a bunch of reactive statements to handle the desired sync operations, but it would be ideal if I could make use of the declarative and succinct Svelte syntax I'm used to.
Logs
No response
System Info
System:
OS: Windows 10 10.0.22000
CPU: (20) x64 13th Gen Intel(R) Core(TM) i9-13900H
Memory: 16.82 GB / 63.66 GB
Binaries:
Node: 20.2.0 - C:\Program Files\nodejs\node.EXE
Yarn: 1.22.19 - C:\Program Files\nodejs\yarn.CMD
npm: 9.6.6 - C:\Program Files\nodejs\npm.CMD
pnpm: 8.6.9 - C:\Program Files\nodejs\pnpm.CMD
Browsers:
Edge: Spartan (44.22000.120.0), Chromium (115.0.1901.203)
Internet Explorer: 11.0.22000.120
npmPackages:
svelte: ^4.0.0 => 4.1.1
Severity
annoyance