Skip to content

Demos

INFO

All components of this page are svelte components, wrappend in custom elements (that's what the plugin does). The Page itself is a vue project. To get a better idea, have a look at the source codes provided and inspect the source code of this page.

Counter

No Svelte Demo without the Counter!

Embedded via <x-counter/>

source code
svelte
<!-- @custom-element x-counter -->
<script lang="ts">
    let count: number = $state(0)
    let props = $props();
    const increment = () => {
        count += 1
    }
</script>
<div class="twp background-color flex flex-col items-center p-6 bg-gray-100 rounded-lg shadow-md max-w-xs mx-auto">
    <button
      onclick={increment}
      class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 shadow-md align-middle m-auto">
        count is {count}
    </button>
</div>

Pokemon Widget

Embedded via <pokemon-widget/>

source code
svelte
<!-- @custom-element pokemon-widget -->
<script lang="ts">
    import {blur} from 'svelte/transition';

    type Pokemon = {
        name: string;
        sprites: { front_default: string };
    };

    let pokemon = $state<Pokemon | null>(null);
    let disableButton = $state(false)
    fetchPokemon();

    async function fetchPokemon() {
        disableButton = true
        const id = Math.floor(Math.random() * 1024) + 1; // Random Pokémon ID
        pokemon = await fetch(`https://pokeapi.co/api/v2/pokemon/${id}`)
            .then((res) => {
                disableButton = false
                return res.json()
            });
    }
</script>

<div class="twp flex flex-col items-center p-6 rounded-lg shadow-md max-w-xs mx-auto">
    <div class="w-20 h-20 object-contain shadow-md rounded-lg">
        {#key pokemon?.name}
            <img transition:blur
                 src={pokemon?.sprites.front_default}
                 alt={pokemon?.name}
                 class={["w-20 h-20 object-contain absolute"]}/>
        {/key}
    </div>

    <div class="w-60 h-10 ">
        {#key pokemon?.name}
            <p class={['text-xl font-semibold capitalize w-60 h-10 text-center absolute']}
               transition:blur>{pokemon?.name ?? "Loading"}</p>
        {/key}
    </div>

    <button onclick={fetchPokemon} disabled={disableButton}
            class="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition w-60"
    >
        Get Random Pokémon
    </button>
</div>

Number Translator

Multiple custom components sharing state.

Embedded via <language-switch/> and <translator-container number="x"/>

source code
ts
type LanguageType = 'en' | 'es';

class NumberTranslator {
    language: LanguageType = $state('en')
    labels = [
        {'en': 'zero', 'es': 'cero'},
        {'en': 'one', 'es': 'uno'},
        {'en': 'two', 'es': 'dos'},
        {'en': 'three', 'es': 'tres'},
        {'en': 'four', 'es': 'cuatro'},
        {'en': 'five', 'es': 'cinco'},
        {'en': 'six', 'es': 'seis'},
        {'en': 'seven', 'es': 'siete'},
        {'en': 'eight', 'es': 'ocho'},
        {'en': 'nine', 'es': 'nueve'},
        {'en': 'ten', 'es': 'diez'}
    ]

    getLanguage() {
        return this.language;
    }

    translate(number: number) {
        return this.labels[number][this.language]
    }

    toggleLanguage() {
        this.language = (this.language == 'en') ? 'es' : 'en';
    }
}

export const numberTranslator = new NumberTranslator();
svelte
<!-- @custom-element language-switch -->
<script lang="ts">
    import {numberTranslator} from "./state.svelte";
    let checked: boolean = $derived(numberTranslator.getLanguage() == 'es')

    function toggleLanguage() {
        numberTranslator.toggleLanguage()
    }
</script>

<div class="twp w-48 rounded-lg">
    <div class="flex items-center mb-5 mx-5 py-1 ">
        <span class="mr-3 text-sm font-medium  ">English</span>
        <label class="relative flex items-center  cursor-pointer">
            <input type="checkbox" value="" class="sr-only peer" {checked} onclick={toggleLanguage}>
            <div class="w-9 h-5 bg-gray-200 hover:bg-gray-300 peer-focus:outline-0  rounded-full peer transition-all ease-in-out duration-500 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all dark:border-gray-600 peer-checked:bg-indigo-600 hover:peer-checked:bg-indigo-700 "></div>
        </label>
        <span class="ml-3 text-sm font-medium  ">Spanish</span>
    </div>
</div>
svelte
<!-- @custom-element translator-container -->
<script lang="ts">
    import Translator from "./Translator.svelte";
    let {number = 0} = $props()
</script>

<div class="twp custom-element background-color flex flex-col items-center p-6 bg-gray-100 rounded-lg shadow-md max-w-xs mx-auto text-sm">
    <span>Number is {number}</span>
    <span>Translation: <Translator {number}/></span>
</div>
svelte
<!-- @custom-element x-translator -->
<script>
    import {numberTranslator} from "./state.svelte";
    let {number: number = 0} = $props();
</script>

{numberTranslator.translate(number)}

Using the same Components, you can also let Svelte components output just text. In this case, the listing is part of the Vue-Page, the words are Svelte.

Embedded via <x-translator number="x"/> and <language-switch/>

Lets count to 5:

Now change the language:

Counter with Shadow-Mode Open

Embedded via <shadow-counter/>

source code
svelte
<!-- @custom-element shadow-counter shadow=open -->
<script lang="ts">
    let count: number = $state(0)
    let props = $props();
    const increment = () => {
        count += 1
    }
</script>
<div>
    <button
        onclick={increment}
    >
        count is {count}
    </button>
</div>