csssvelte-3svelte-transition

How to use two svelte transitions on the same togglable element?


I have an input field that I want to hide/show and doing so with a fade and slide transition. I've have two examples that I came up with but both have their drawbacks and I'd like to know if there is a more elegant solution.

I just need one of the two questions to be answered as both of them would solve my problem.

Question 1: Is there a way to trigger multiple transitions for one transition-directive?

Question 2: How to add a class that will trigger an ordinary css-transition after an if-statement put the element in the DOM?

Example 1

Svelte does not allow two transitions on the same element. So one solution is to nest two elements as shown below. Is there instead a way to write a custom transition using both fade and slide transition:myMultiTransition?

{#if active === true}
  <span transition:fade>
    <span transition:slide>
      <input type="text" />
    </span>
  </span>
{/if}

Example 2

In my other solution I just toggle an active class using a normal css transitions. The problem here is that the <input>-field never leaves the DOM. It's 0px height but it seems wrong to leave it there.

How to cuccessfully show the input field with an {#if active === true} and afterwards add a class that trigger the transition effect? Svelte seems to add the active-class that is supposed to trigger the transition before the element has entered the DOM.

I've tried to use await tick(), onMount, beforeUpdate in various combination with no luck.

When adding the class with a delay with setTimeout it works - but I don't like this solution because it could fail if not the timing is exact and I won't want a delay before the transition start.

<span class:{active}>
   <input type="text" />
</span>

<style>
  .active {
     // Normal transition: opacity 1s etc ... 
  }
</style>

REPL

https://svelte.dev/repl/89cb7d26d9484d0193b4bc6bf59518ef?version=3.38.3


Solution

  • You can create your own transition function:

    <script>
        import { cubicOut } from 'svelte/easing';
        let visibleDoubleElements = false;
    
    
        function slidefade(node, params) {
            const existingTransform = getComputedStyle(node).transform.replace('none', '');
    
            return {
                delay: params.delay || 0,
                duration: params.duration || 400,
                easing: params.easing || cubicOut,
                css: (t, u) => `transform-origin: top left; transform: ${existingTransform} scaleY(${t}); opacity: ${t};`
            };
        }
    </script>
    
    
    <label>
        <input type="checkbox" bind:checked={visibleDoubleElements}>
        Svelte transition
    </label>
    
    {#if visibleDoubleElements === true}
        <input transition:slidefade type="text" placeholder="Double elements" />
    {/if}
    
    

    REPL: https://svelte.dev/repl/da8880947eff4f32b740a8742d9f817e?version=3.38.3