39
loading...
This website collects cookies to deliver better user experience
props
defined in Svelte components compiles to an attribute of a custom element. In HTML, most of the attributes are named in kebab-case
, specified as words in lower alphabets combined with -
1.props
are described as a set of declaration of variables, which in JavaScript cannot include -
in the name. This is known issues2 with a workaround.$$props
to access the props like $$props['kebab-attr']
in these situations2.props
should be undefined
at that moment the component has been instantiated, unintentionally.// App.svelte
<script>
import './Kebab.svelte'
let name = value
</script>
<input bind:value>
<swc-kebab your-name={name}></swc-kebab>
// Kebab.svelte
<svelte:options tag="swc-kebab" />
<script>
export let yourName = $$props['your-name']
</script>
Hello, {yourName}
<swc-kebab your-name={name}></swc-kebab>
is to have a wrapper class to intercept default behavior of the Svelte3:// KebabFixed.js
import Kebab from './Kebab.svelte'
class KebabFixed extends Kebab {
static get observedAttributes() {
return (super.observedAttributes || []).map(attr => attr.replace(/([a-zA-Z])(?=[A-Z])/g, '$1-').toLowerCase());
}
attributeChangedCallback(attrName, oldValue, newValue) {
attrName = attrName.replace(/-([a-z])/g, (_, up) => up.toUpperCase());
super.attributeChangedCallback(attrName, oldValue, newValue);
}
}
customElements.define('swc-kebab-fixed', KebabFixed);
// App.svelte
<script>
import './KebabFixed.svelte'
let name = value
</script>
<input bind:value>
<swc-kebab-fixed your-name={name}></swc-kebab-fixed>
yourName="some value"
, it will be converted to a lower-case version like yourname
. yourName
as usual would result undefined
.yourName
to yourname
fixes it to work properly. Unlikely, the attribute name on caller side doesn't matter, whichever it is yourName="camelCase"
or yourname="non camel case"
.// App.svelte
<script>
import './NoUppercase.svelte'
let name = value
</script>
<input bind:value>
<swc-no-uppercase yourName={name}></swc-no-uppercase>
// NoUppercase.svelte
<svelte:options tag="swc-no-uppercase" />
<script>
export let yourName // Change this to `yourname`
</script>
Hello, {yourName} <!-- Change this to `yourname` -->
value
propagates to name
in the child component which depends to value
.yourname={name}
. The only way to set attribute values is to code yourname="a string literal"
directly. Use DOM APIs to change these attribute values dynamically:const element = document.querySelector('swc-child')
element.yourName = 'a updated name'
attributeChangedCallback
which Svelte registered propagates the change to the internal DOM of the custom element. This enables you to treat the custom element similarly to Svelte components.bind:
mechanism in custom elements. Changes in child custom elements will not be available to parent components.props
. But attribute values in HTML accept just a literal string.// App.svelte
<svelte:options tag="swc-root" />
<script>
import PassAnObjectFixed from './PassAnObjectFixed.svelte'
let name = 'default name'
window.__myData = {
'somekey': {}
}
$: window.__myData['somekey'].name = name
const syncToParent = () => {
name = window.__myData['somekey'].name
}
</script>
<input bind:value={name}>
{name}
<p>As WC: <swc-pass-object name={data}></swc-pass-object></p>
<p>As Svelte: <PassAnObject {data} /></p>
<p>As WC: <swc-pass-object-fixed key="somekey"></swc-pass-object-fixed><button on:click={syncToParent}>Sync to input field</button></p>
// PassAnObjectFixed.svelte
<svelte:options tag="swc-pass-object-fixed" />
<script>
export let key
let name
const refresh = () => {
name = window.__myData['somekey'].name
}
refresh()
$: window.__myData['somekey'].name = name
</script>
Hello, {name} <button on:click={refresh}>Refresh</button>
<input bind:value={name}>
bind:
in anyway.on:click
, on:keydown
or on:focus
.addEventListener
wouldn't be able to catch them since they're built on Svelte-specific event mechanism. In the example below, you can see how a custom event, which is successfully listened in Svelte event handler, doesn't fire the callback registered via addEventListener
.// App.svelte
<svelte:options tag="swc-root" />
<svelte:window on:load={() => handleLoad()} />
import CustomEventExample from './CustomEventExample.svelte'
let name = 'default name'
const handleCustomEvent = (event) => name = event.detail.name
let rootElement
const handleLoad = () => {
const customElement = rootElement.querySelector('swc-custom-events')
customElement.addEventListener('namechanged', handleCustomEvent)
}
$: if (customEventElement) customEventElement.name = name
</script>
<div bind:this={rootElement}>
<h1>Custom Event</h1>
<p>As Svelte: <CustomEventExample {name} on:namechanged={handleCustomEvent} /></p>
<p>As WC: <swc-custom-events name={name}></swc-custom-events></p>
</div>
// CustomEventExample.svelte
<svelte:options tag="swc-custom-events" />
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
export let name
$: (name) && dispatch('namechanged', { name })
</script>
Hello, {name}
<input bind:value={name}>
<svelte:options tag="swc-custom-events-fixed" />
<script>
import { createEventDispatcher } from 'svelte';
import { get_current_component } from 'svelte/internal';
const component = get_current_component();
const originalDispatch = createEventDispatcher();
const dispatch = (name, detail) => {
originalDispatch(name, detail);
component?.dispatchEvent(new CustomEvent(name, { detail }));
}
export let name
$: (name) && dispatch('namechanged', { name })
</script>
Hello, {name}
<input bind:value={name}>
<svelte:options tag="tag-name" />
will have a shadow root.<style>
section will be extracted and merged into the parent's one. Thus,// App.svelte
<svelte:options tag="swc-root" />
<script>
import StylesEncupsulated from './StylesEncupsulated.svelte'
let name = 'default name'
</script>
<h1>Styles</h1>
<p>As Svelte: <StylesEncupsulated {name} /></p>
<p>As WC: <swc-styles-encapsulated name={name}></swc-styles-encapsulated></p>
// StylesEncupsulated.svelte
<svelte:options tag="swc-styles-encapsulated" />
<script>
export let name
</script>
<span>Hello, {name}</span>
<style>
span { color: blue }
</style>
// StylesEncupsulated.svelte
<svelte:options tag="swc-styles-encapsulated" />
<script>
export let name
</script>
<span style="color: blue;">Hello, {name}</span>
createElements.define
to register custom elements. If you enabled customElement
in compiler options, there's no way to control which component should be compiled to a custom element and which is not.Uncaught (in promise) TypeError: Illegal constructor at new SvelteElement
if you misses <svelte:options tag="swc-styles-encapsulated" />
in any component inside the project.4