Search code examples
svelteinnerhtmlsveltekit

Manipulate innerText in a slot while keeping slot style with svelte


I want to make a component that makes a typewriter effect, but I need to keep the styling inside the slot so I can use any text style with the same effect.

Main file :

<TypewriterText>
    <h1>Hey what's up!</h1>
</TypewriterText>

TypewriterText.svelte :


<script>
    import { onMount } from 'svelte';

    let content = '';
    let currentText = '';
    let currentIndex = 0;

    onMount(() => {
        const data = document.querySelector('.hidden');
        content = data?.innerText || '';
        typeWriter();
    });

    function typeWriter() {
        if (currentIndex < content.length) {
            currentText += content.charAt(currentIndex);
            currentIndex++;
            setTimeout(typeWriter, 10);
        }
    }
</script>

<span class="hidden"><slot /></span>
{currentText}

<style>
    .hidden {
        display: none;
    }
</style>

The only way I found is to hide the slot and reproduce the innerText below. But this way I lose the html tag...

Thx a lot !!


Solution

  • You have to switch h1 and TypewriterText so it applies the styling before the text effect.

    <h1>
       <TypewriterText>Hey what's up!</TypewriterText>
    </h1>
    

    Also, using an action would be more suited to your need.

    <script>
        const typewriter = node => {
            let timeout = undefined;
            const fullText = node.textContent;
            node.textContent = '';
            type();
    
            function type() {
                if (node.textContent.length >= fullText.length)
                    return;
    
                node.textContent = fullText.substring(0, node.textContent.length + 1);
                timeout = setTimeout(type, 100);
            }
    
            return { destroy() { clearTimeout(timeout); } }
        }
    </script>
    
    <h1 use:typewriter>Hello there</h1>
    

    REPL