Svelte Tutorials Learning Notes: Transitions
Tags: svelte, javascript, beginners
Published: 2020-01-21 21:05:06

> __Note about this format:__ I found that writing “explainer” notes gave me a stronger, deeper understanding of whatever I was learning. On the other hand, I often felt stupid for having to slow down and spell things out; for not grokking _everything_ immediately, magically, effortlessly 🙃. 

> In the spirit of the new(ish) year, I figured sharing my learning notes publicly might be beneficial: it would hold myself accountable to get ahead with my learning, it would hopefully send the message that learning in this manner is nothing to be embarassed about, and lastly, who knows my notes could help other folks!

> Last thing: As these are _personal notes_ rather than fully-fledged articles, I write from my perspective as a learner. Also, I’m still experimenting with how to balance brevity, practicality, _and_ clarity when discussing code examples. For now, I’m taking the most simple way: code blocks truncated to relevant parts, code comments for short explanation, and bullet points underneath for longer ones. Let’s see how it goes!

🌳🍃

I’ve been trying to get more practice with basic animation as it’s one of my weakest points. As I happen to be learning [Svelte](https://svelte.dev), I looked up how to implement it in Svelte. Turns out Svelte has several built-in modules for motion-related functionalities: `svelte/motion`, `svelte/transition`, and `svelte/animate` — which means that we don’t need to install third-party animation library for basic use cases! 👍🏽

Svelte has an excellent [Tutorial section](https://svelte.dev/tutorial) with live editable sandbox. In this note, I’m going through the tutorials on __Transition__, which consists of:

a) The transition directive
b) Adding parameters
c) In and out
d) Custom CSS transitions
e) Custom JS transitions
f) Transition events
g) Local transitions
h) Deferred transitions

---

## Before we begin…

* **Huh? Directives?** Svelte makes extensive use of “directives”, which resemble [attributes/properties](https://javascript.info › dom-attributes-and-properties) and _“control the element’s behaviour in some way”_. This was new to me and I found the syntax rather strange, to be honest. 😁
	- Also see: [list of all directives](https://svelte.dev/docs#Element_directives)
* Make sure you disable all animations using `@media (prefers-reduced-motion: reduce)` for users who prefers not to see motion.
	- Further read: [Move Ya! Or maybe, don't, if the user prefers-reduced-motion!](https://developers.google.com/web/updates/2019/03/prefers-reduced-motion)
* If you’ve never used CSS `transitions` before, check out [CSS Tricks’ explainer on CSS transition](https://css-tricks.com/almanac/properties/t/transition/) and [animation](https://css-tricks.com/almanac/properties/a/animation/) to familiarize yourself with basic concepts like delay, duration, and easing.
* Further reads on UI motion:
	- [Understanding motion - Material Design](https://material.io/design/motion/understanding-motion.html)
	- [The Role of Animation and Motion in UX by Page Laubheimer](https://www.nngroup.com/articles/animation-purpose-ux/)


---

## a) The transition directive

💻 Try it: https://svelte.dev/tutorial/transition

This is our very first introduction to Svelte transitions! 

- There are six transition functions we can import: `fade`, `fly`, `slide`, `scale`, `draw` and `crossfade` ([see docs](https://svelte.dev/docs#svelte_transition)). 
	- eg. `import { fade } from 'svelte/transition';`
- We use it in our element with the `transition` directive, eg. `<p transition:fade>`.
	- Also see: [transition directive API](https://svelte.dev/docs#transition_fn)
- In this example, the transition is activated conditionally from a checkbox input with `bind:checked` directive. The checkbox is tied to a state variable called `visible`, whose value comes from the checkbox `checked` state. If true (ie. if checked), `fade` the element in, and if false, `fade` it out.
	- Different events could be used to activate the `fade` function (eg. button click), but it does not work if not tied to any event.
	- It also does NOT run automatically when the component is mounted/initialized. 

```html
<!-- ❌ Does not work, don't copy -->
<script>
  import { fade } from 'svelte/transition';
</script>

<p transition:fade>
  Does not fade in and out
</p>
```

```html
<!-- ✔️ Works -->
<script>
  import { fade } from 'svelte/transition';

  // Initiate variable, visible by default
  let visible = true; 
</script>

<label>
  <!-- Update checked state and "visible" variable. If checked is true, visible is true. -->
  <input type="checkbox" bind:checked={visible}> visible
</label>

{#if visible}
  <p transition:fade>
    Fades in and out
  </p>
{/if}
```

---

## b) Adding parameters

💻 Try it: https://svelte.dev/tutorial/adding-parameters-to-transitions

- This example uses a different function, `fly`, to demonstrate passing optional parameters to the function. 
	- Each of the six functions takes different parameters, which are listed in the [official API docs](https://svelte.dev/docs#svelte_transition). All functions have two common parameters, `delay` and `duration`.
* Without parameters (previous example) = `<p transition:fly>`
* With parameters = `<p transition:fly="{{ y: 200, duration: 2000 }}">`
	* `y: 200` means the element is animated from 200px under its supposed position, to its supposed position. If we changed it to `y: -100`, the element flies down from 100px above its supposed position.
- There’s a note about transition being “reversible”: _“if you toggle the checkbox while the transition is ongoing, it transitions from the current point, rather than the beginning or the end”_. 
	- To see this in action, I changed `duration` value to a much larger value (eg. `8000`) and clicked the checkbox halfway through the transition. Confirmed!
	- It’s a nice touch to ensure smooth visual transition (no “jumping”) even if user triggers/toggles the transition states repeatedly.

---

## c) In and out

💻 Try it: https://svelte.dev/tutorial/in-and-out

- In the previous two examples, the  `transition` directive applies to *a pair* of transitions, eg. `fade` from 0 opacity to 1 (when entering the DOM / `visible` is set to `true`), and the other way around from 1 to 0.
- In this part, we learn that we can define individual transition using  `in` and `out` instead of  `transition`. Therefore, we can run different functions, eg. `fly` when entering the DOM and `fade` when leaving: `<p in:fly="{{ y: 200, duration: 2000 }}" out:fade>`. Convenient!
- This page also says that in contrast with `transition` directive, `in` and `out` transitions are not “reversible”. 🤔 Huh?
	- You can see the difference by running and comparing two code snippets below. (The `<script>` part and `{#if}` block are identical.)

```html
<p 
  in:fly="{{ y: 100, duration: 5000 }}" 
  out:fly="{{ y: 100, duration: 5000 }}"
  >
	Flies in and out 
</p>
```

```html
<p 
  transition:fly="{{ y: 100, duration: 5000 }}" 
  >
	Flies in and out 
</p>
```

* Although the transition functions are identical in both codes (ie. `fly`), they behave differently. I deliberately set long duration so the transitions are more apparent.
	* With `in` and `out`: If you uncheck the checkbox and quickly check it _in the middle of the transition_ (while the text element is halfway flying out/down), the text element starts the opposite transition (flying back in/up) from the bottom, NOT the middle. This creates a visual “jump”.
	* With `transition`: If you do the same thing, the text element starts the opposite transition (fly back up) right from its current position. If you check/uncheck repeatedly,  it creates a smooth “bouncing” visual.
	* Thus we can conclude `in` and `out` are strictly for _different_ transition types.

---

## d) Custom CSS transitions

💻 Try it: https://svelte.dev/tutorial/custom-css-transitions

☕️ This part is rather long. Get yourself a beverage of your choice, if you want.

- Svelte provides common transitions like `fade` and `slide` as built-in functions (details in part (a))—but what if we need something more complex? In this part, we learn to create a *custom transition function*.
- You can see the function API in [the tutorial](https://svelte.dev/tutorial/custom-css-transitions).
	- It takes 2 arguments: the node object and passed parameters object
	- It return 5 properties:
		- `delay`
		- `duration`
		- `easing`
		- `css`
		- `tick`

Here I’m annotating the first example, the build-in `fade` function.

```js
/**
 * Example 1 of CSS transition function
 * 
 * @param node {Node} - The node we're applying transition to.
 * @param {object} - Parameters we can pass in this function.
 */

function fade(node, {
  // Set default value for "delay" and "duration" parameters.
  delay = 0, // 0 ms before the transition begins
  duration = 400 // Transition lasts for 400 ms
}) {
  // Get the node object's opacity
  const o = +getComputedStyle(node).opacity;

  // Return a transition object with these properties
  return {
    // User-passed parameters for "delay" & "duration"
    delay,
    duration,

    // Generate CSS animation; in this case animate the opacity
    css: t => `opacity: ${t * o}`
  };
}
```

Let’s have a closer look at what’s happening here.

- First we define the function `fade` with two arguments:
	- `node` is the node we are applying transition to, eg. `<div transition:fade>`
	- An object containing parameters that user can pass when calling this function, eg. `<div transition:fade="{{duration: 400}}">`. Here we have two parameters, `delay` and `duration`.
		- It’s optional; you can omit the second argument, like so: `function foo(node) { ... }`. 
		- If your function does not return `delay` and `duration`, the function won’t break; default values will be used. 
		- Here we set our custom default values of `0` and `400` respectively. 
- Then we get our node’s CSS opacity value and save it to variable `o`. We use  `getComputedStyle`, a [vanilla JavaScript method](https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle) (ie. not a Svelte thing). By default (and in this example), an element has an opacity of `1` . 
- What does the `+` sign before  `getComputedStyle` do? TL;DR: _“It forces the parser to treat the part following the + as an expression [rather than declaration]”_ ([source](https://stackoverflow.com/a/13341710)). 
	- It’s called _Immediately-Invoked Function Expression (IIFE)_ , which [Ben Alman explains at length in this article](http://benalman.com/news/2010/11/immediately-invoked-function-expression/). And it doesn’t have to be `+`; it can be any unary operator (`-`, `!`, etc). This is new to me! 
- Last, we return a transition object with these properties: `delay`, `duration`, and `css` . The first two are self-explanatory; now we’re taking a closer look at the `css` property.
- `css` is a function that generates CSS animation. The function takes two arguments, `t` and (optional) `u`, where `u === 1 - t`.
	- At **intro** (eg. fade in), `t` value goes from 0 to 1. `u` goes the opposite way from 1 to 0.
	- At **outro** (eg. fade out), `t` value goes from 1 to 0. Vice versa with `u`.
- Our example generates _fade in_ animation like this: (and _fade out_ animation that does the opposite way)

```css
0% { opacity: 0 }
10% { opacity: 0.1 }
20% { opacity: 0.2 }
/* ... */
100% { opacity: 1 }
```

- The opacity value is calculated from `t * o` in the `css` function. It’s quite straightforward: at 10% through the duration, `t = 0.1`, so we get `0.1 * 1 = 0.1`.
	- What’s the point of multiplying with `o` though? If our node has an opacity of `0.5`, this function can generate the appropriate keyframes, eg. opacity value of  `0.1 * 0.5 = 0.05` at 10%.

Unfortunately this example does not return the `easing` and `tick` properties, so at this point I’m not sure how they work. 

Next, let’s go through the second, more complex example! 🤞🏾

```js
/**
 * Example 2 of CSS transition function
 * 
 * @param node {Node} - The node we're applying transition to.
 * @param {object} - Parameters we can pass in this function.
 */

function spin(node, { duration }) {
  return {
    duration,
    css: t => {
      // Create easing that lasts through the transition (starting point = when transition starts, finish point = when transition ends).
      const eased = elasticOut(t);

      return `
        transform: scale(${eased}) rotate(${eased * 1080}deg);
        color: hsl(
          ${~~(t * 360)},
          ${Math.min(100, 1000 - 1000 * t)}%,
          ${Math.min(50, 500 - 500 * t)}%
        );`
    }
  };
}
```

What is happening here?

* Like in the first example, we define our `spin` function and pass two arguments: `node` and object containing `duration` parameter (no default value here), which returns our transition object with two properties: `duration` and `css`. 
* Now let’s have a closer look at the `css` function. 
	* First, we notice that we use another built-in function, `elasticOut`, imported from `svelte/easing`. We pass `t` into the function (see explanation on `t` in the first example) and save it in the `eased` variable. Learn more: read [the docs on easing](https://svelte.dev/docs#svelte_easing). 
	* From the docs: _“Easing functions specificy the rate of change over time and are useful when working with Svelte’s built-in transitions and animations […]“_
	* In a nutshell, `elasticOut` is an easing variant that starts with a sharp “bounce” down and up, a less marked drop, then goes almost linear afterwards.

![Graph showing the elasticOut easing function](https://thepracticaldev.s3.amazonaws.com/i/6xumsz7ig8dpzy16n71d.jpg)
<figcaption>Graph of the elasticOut function</figcaption>

- Next, we see that we animate TWO properties: `transform` and `color`. These properties use `eased` value, which implements the `elasticOut` behaviour on these transitions.
	- The `transform` property has TWO functions as value: `scale` and `rotate`. 
		- `scale(${eased})` means the element increases sharply in size (ie. becomes very large), then decreases until it’s smaller than its final size, then another set of *slight* increase and decrease, then ends at its final size.
		- `rotate` is slightly harder for me to understand at first. Changing the rotate multiplier value from `rotate(${eased * 1080}deg)` to  `rotate(${eased * 90}deg)` helps me observe and understand its behaviour. Like `scale`, the `rotate` value increases (ie. rotate clockwise) then decreases into negative (ie. rotate counter-clockwise), and so on. 
		    - Note that since the final value of `eased` is `1`, if the multiplier value is not divisible by 360, eg. `eased * 90`, it ends at 90 degree then “jumps” back to 0 degree (as the animation is removed after the transition is finished). Therefore, to create a smooth animation, make sure the multiplier is 360 or its multiples (720, 1080, etc). 
		    - Rotating an element to 360 degrees = rotating it one full circle. It means, if the multiplier value in our function is `720`, we spin the element _twice_ as many as when the value is `360`. Increase the multiplier (360, 720, 1080, 1440) to see how it works. _[WARNING: If you are sensitive to quick flashy motion, increase the duration as well.]_
	* For `color`, we use HSL, a CSS color format that takes three values for *Hue*, *Saturation*, and *Luminosity*. It’s a CSS function, not a Svelte-exclusive thing, so we can use this elsewhere. To learn more about what each value does, read [CSS Tricks’ article on HSL](https://css-tricks.com/hsl-hsla-is-great-for-programmatic-color-control/).
		* Hue: `${~~(t * 360)}` 
			* The double tilde `~~` operator stumped me. I look it up and found the answers in these StackOverflow posts: [this](https://stackoverflow.com/questions/5971645/what-is-the-double-tilde-operator-in-javascript), [this](https://stackoverflow.com/questions/4055633/what-does-double-tilde-do-in-javascript), and [this](https://stackoverflow.com/questions/32607970/what-is-in-javascript). Basically it works like `Math.floor`, ie. convert floating-point numbers (or strings) to integer. Our `hue` value `t * 360`  goes from `0` to `360`. The double tilde operator ensures the animation keyframes are 0, 1, 2, 3, …, 360 rather than 0, 0.0001, 0.0002, etc.
		* Saturation: `${Math.min(100, 1000 - 1000 * t)}%`
			* [Math.min](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min) is a function that returns the lowest-valued number passed to it. Saturation value should begin from 100% (because `1000 - 1000 * 0` = `1000`, which is greater than `100`), and decreases once `t` goes _above_ `0.9` (eg. when `t = 0.92`, we have `1000 - 1000 * 0.92` = `80`). For some reason I don’t see the visual result of saturation decreasing, though.
		* Luminosity: `${Math.min(50, 500 - 500 * t)}%`
			* Similar to saturation, just with different value.

That’s it! Here we’ve learned how to create visually complex transitions by leveraging and combining various CSS properties and functions.


---

## e) Custom JS transitions

💻 Try it: https://svelte.dev/tutorial/custom-js-transitions

This part literally starts with a warning to _only_ use JavaScript transitions to create effects that can’t be achieved otherwise 😆. Indeed, using CSS to animate supported properties (eg. opacity, color, transform) is better for performance because CSS animations are “handled by the browser's compositor thread rather than the main thread responsible for painting and styling” ([source](https://www.keycdn.com/blog/animation-performance)). 

In this example, we are creating a `typewriter` effect: each letter of the text element appears one by one on-screen. JS is needed for this transition because:
- the duration depends on the text length (the longer the text, the longer it takes until the last character appear); and…
- we have to render each letter individually to the DOM.

```js
/**
 * Example of JS transition function
 * 
 * @param node {Node} - The node we're applying transition to.
 * @param {object} - Parameters we can pass in this function.
 */

function typewriter(node, { speed = 50 }) {
  // Check if our node contains text AND no nested child elements
  const valid = (
    node.childNodes.length === 1 && node.childNodes[0].nodeType === 3
  );

  if (!valid) {
    throw new Error(`This transition only works on elements with a single text node child`);
  }

  // Get node text content
  const text = node.textContent;
  // Get duration based on text length (longer text = longer duration it takes for each letter to appear one by one)
  const duration = text.length * speed;

  return {
    duration,
    tick: t => {
      const i = ~~(text.length * t);
      node.textContent = text.slice(0, i);
    }
  };
}
```

Let’s go through the code.

- We define our `typewriter` function and pass two arguments: `node` and object containing `speed` parameter with default value of `50`.
- The node element must pass these two conditions in order to be valid:
	- `node.childNodes.length === 1` means our node must only contain one child node ([see reference](https://developer.mozilla.org/en-US/docs/Web/API/Node/childNodes)); and…
	- `node.childNodes[0].nodeType === 3` means our child node must be text.
	- ✔️ Example: `<p in:typewriter>Hello!</p>`
	- If the node is not valid, we throw an error.
- After ensuring our node is valid, we get the text content and save it to the `text` variable.
- We get the `duration` by multiplying text length and `speed` parameter.
	- eg. If our element consists of 6 characters and the speed is 50; the transition `duration` is 6 * 50 = 300ms.
	- (Yes, larger `speed` value means the transition takes _longer_ to complete 😬. Test it by changing `speed` value to eg. `500`.)
- We return our transition object with two properties: `duration` and `tick`.  The former is self-explanatory, while the latter is something we haven’t seen in previous examples!
	- From the [API docs](https://svelte.dev/docs#Custom_transition_functions): _“If it’s possible to use `css` instead of `tick`, do so — CSS animations can run off the main thread, preventing jank on slower devices.”_
- In the [previous tutorial](https://svelte.dev/tutorial/custom-css-transitions), `tick` is defined as “a `(t, u) => {...}` function that has some effect on the node”. Huh? 🤔
	- We are familiar with `t` and the `~~` operator from the previous examples, though. Go back to the previous section if you’d like a refresher on what these do.
	- Say we want to animate the text *“Hello!”*, which consists of 6 characters. First we get `i` value by multiplying `t` and `text.length`. In the beginning, `i` is 0 * 6 = 0; and it increases until  `i` is 1 * 6 = 6. 
	- We use `~~` to make sure `i` is an integer—we want `0, 1, 2, 3, …, 6` instead of 0, 0.00001, 0.00002, etc.
	- Next, we generate the transition by rendering the [sliced](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) text values in `node.textContent` :
		* `text.slice(0,0)` —> `""`
		* `text.slice(0,1)` —> `"h"`
		* `text.slice(0,2)` —> `"he"`
		* `text.slice(0,3)` —> `"hel"` (etc)
	- These are done within the `duration` of 300ms.


---

## f) Transition events

💻 Try it: https://svelte.dev/tutorial/transition-events

Svelte provides four transition-related events that we can listen for:
1. `introstart`
2. `outrostart`
3. `introend`
4. `outroend`

- The names are quite self-explanatory: the `introstart` event fires when the “in” transition starts (eg. when the element flies/fades/slides in), and so on.
- We listen for these events using the `on` directive. You can run _any expression/function_ in the directive parameters, like with eg. `onclick` event. (In the tutorial’s original example, we update the `status` value.)
    - To learn more about events, see [MDN Docs on Event](https://developer.mozilla.org/en-US/docs/Web/API/Event).

Example of an element that listens for transition events.

```html
<p
  transition:fly
  on:introstart="{() => console.log('Starting intro!')}"
  on:outrostart="{() => status = 'outro started'}"
  on:introend="{() => doSomething()}"
  on:outroend="{() => doSomethingElse()}"
>
  Hello world!
</p>
```

Don’t forget to  define the corresponding variable and functions in the `<script>` part like so:

```js
let status = 'waiting...';

function doSomething() {
  // do something...
}

function doSomethingElse() {
  // do something else...
}
```

I find this helpful as many web UI transitions involves multiple elements—a basic example is how we animate the heading title, then the subtitle, body text, and the image one after another. 

---

## g) Local transitions

💻 Try it: https://svelte.dev/tutorial/local-transitions

- __Local transition__ is a transition that _“only plays when the immediate parent block is added or removed”_. 
- We learn a new syntax here: `local` is called “modifier” and added in the transition directive, separated with `|`.
	- Example: `<div transition:slide|local>`
	- With parameter: `<div transition:slide|local="{{ duration: 300 }}">`

Let’s look at the example: (the `<script>` part truncated)

```html
<label>
  <!-- Toggles showItems value when checked (true) / unchecked (false). Same as previous examples. -->
  <input type="checkbox" bind:checked={showItems}> show list
</label>

<label>
  <!-- Renders a “slider” from 0 to 10, which saves user-selected value to i. -->
  <input type="range" bind:value={i} max=10>
</label>

<!-- Render list if showItems === true -->
{#if showItems}
  <!-- Loop through the first i items. (If i is 3, loop through the first three items.) -->
  {#each items.slice(0, i) as item}
    <!-- Add "slide" local transition -->
    <div transition:slide|local>
      <!-- Print string from the "items" array defined in line 6. -->
      {item}
    </div>
  {/each}
{/if}
```

- When we _check the checkbox_ and the `showItems` value changes from `true` (ie. show list) to `false` (hide list) or vice versa, the `slide` transition is NOT run. The list (“one, two, three” etc) simply appears and appears without transition.
- However, when we _drag the slider_ left or right, increasing or decreasing the `i` value, the list item is animated using the `slide` transition (slide down when appearing, up when disappearing). It’s because `{#each items.slice(0, i) as item}` is the _direct parent_ of `<div transition:slide|local>`!

I initially did not quite get what’s so special about local transitions compared to the default ones. I guess it boils down to:
- Performance (no need to run transition effects if not necessary)
- (Maybe?) Not tire out users with too much motion, unless it really communicates something relevant to the interaction/interface—which most likely come from its direct parent.
- All in all, perhaps it’s about having a built-in helper to _control_ when a particular transition occurs. When we don’t need to run it _all the time_, we can restrict it to its parent simply by adding `|local`. Niice!

---

## h) Deferred transitions

💻 Try it: https://svelte.dev/tutorial/deferred-transitions

This is the last part of the Transitions tutorial! 

The example code seems long and super complex at first glance (or it does to me), but most of the its length can be attributed to the “to do” functionalities rather than the transition being discussed.

So: What is a __deferred transition__? 

- The tutorial page describes it as _“the ability to *defer* transitions, so that they can be coordinated between multiple elements.”_
- _“If a transition returns a function instead of a transition object, the function will be called in the next microtask. This allows multiple transitions to coordinate, making crossfade effects possible.”_  — https://svelte.dev/docs#Custom_transition_functions

Here’s the JS code of the deferred transition.

```js
const [send, receive] = crossfade({
  // Sending/receiving transition duration (we can also define "delay" and "easing")
  duration: d => Math.sqrt(d * 200),

  // Optional fallback transition function if the crossfade pair lacks one part (missing "sending" OR "receiving" element)
  fallback(node, params) {
    const style = getComputedStyle(node);
    const transform = style.transform === 'none' ? '' : style.transform;
    return {
      duration: 600,
      easing: quintOut,
      css: t => `
        transform: ${transform} scale(${t});
        opacity: ${t}
      `
    };
  }
});
```

Then we have two sets of arrays (first is unfinished todo items `todos.filter(t => !t.done)`, second is finished todo items) that render the element below. The `label` element _is identical_ for both finished and unfinished items, except the former has `class="done"` for styling. 

```html
<label
  in:receive="{{key: todo.id}}"
  out:send="{{key: todo.id}}"
>
  <!-- input field -->
</label>
```

Let’s break down the JS code:

- We assign the `crossfade` function to a pair of variables called `send` and `receive`.
- If you’re not familiar with the syntax `const [send, receive]` , it’s called _“destructuring assignment”_. This is a [good article](https://dev.to/sarah_chima/destructuring-assignment---arrays-16f) about it.
	- In case you’re curious: We _can_ assign the `crossfade` function to a different variable name without destructuring if we want.
		- eg. Instead of `const [send, receive]`, we can write  `const crossfadeArray = crossfade({ … });`
		- Don’t forget `crossfadeArray` is, well, an array. 
			- I tried and found that we CANNOT use `crossfadeArray[0]` in the directive like `<label in:crossfadeArray[1]="{{key: todo.id}}" in:crossfadeArray[0]="{{key: todo.id}}">`.
			- What we CAN do is assign the pair into a variable each, eg. `const send = test[0];` and `const receive = test[1];`. 
			- The variable names don’t even have to be `send` and `receive`; it can be anything—eg. `foo` and `bar`—as long as you call them correctly, eg. `<label in:bar="{{key: todo.id}}" in:foo="{{key: todo.id}}">`.
		- Now we can see why it’s cleaner to use the destructuring assignment like in the original example.
- Back to `crossfade`! I still haven’t completely understood it, so I play around with the code (modify the durations to absurdly high values to see what changes), and… log `send` and `receive` to the console. 😬🤷🏽‍♀️
	- Both variables simply print `function transition()`.
	- In previous examples, we’ve used transition functions after `in` and `out` directives, eg; `in:fade`, `in:typewriter`, `in:anyCustomTransition`. Only after I tried the above steps did I realise… this is just like that! The only difference being we don’t have the actual returned transition object yet until a particular item is marked done (ie. “sent out” from one section and “received in” another), because it is… _deferred_. 🤯 Yay!
		- What does this transition do though? As described in the tutorial page, it  _“transforms the element to its counterpart’s position and fades it out”_, ie. it animates the `transform` and `opacity` CSS properties. 👌🏾
- `crossfade` takes a single object as argument, which contains: 
	- `duration` — the duration of the “send/receive” transitions (in this case: when an item in the unfinished todo list is checked and thus “sent” to the finished list OR vice versa).
		- `Math.sqrt` = get square root of `d * 200` .
	- `fallback` — the function that runs when the “send/receive” pair is incomplete, ie. missing either “sending” or “receiving” element (in this case: adding a new item to the todo list and deleting an item from either list, respectively).
		- This is a regular transition function like the ones we encounter in previous examples—it takes two arguments: `node` and `params`; returns object containing `duration`, `easing`, `css`.
		* It’s optional—ie. does not cause error if removed. If removed, the “send/receive” transitions (moving items between unfinished and finished lists) run just fine; but the unpaired transitions (adding or deleting items) run without transition.
		* `easing: quintOut` is an easing style that you can see in the [Easing Visualizer](https://svelte.dev/examples#easing). We can replace it with any other easing styles.
* 🙆🏽‍♀️ Wait a minute! We only use `duration` in this example—but what other properties can the `crossfade` object have?
	* The API docs does not state explicitly, but since `crossfade`  is a transition object, let’s assume it can have all transition object’s properties: `delay`, `duration`, `easing`, `css` and `tick`.
	* The first three properties work as expected (see example below). I half-heartedly tried `css` but it did not seem to work. Did not try `tick`.

The `const [send, receive]` code block in the example can be replaced (and run without error) with this:

```js
const [send, receive] = crossfade({
  // When we check/uncheck a list item, wait 1s before moving/animating it.
  delay: 1000,
  // The list item moves soooo slowly.
  duration: d => Math.sqrt(d * 4000),
  // The list item does a little jiggly move (don't forget to import { elasticOut } from 'svelte/easing' if you're trying this!).
  easing: elasticOut

  // No fallback function means adding and deleting items don't get animated.
});
```

From this part, I particularly really like this description: 

> Using motion can go a long way towards helping users understand what’s happening in your app.

Not _all_ web pages need complex, stunning, artistic animations.  But motion is also needed in “regular” UI for the reason described above. Its presence may be barely noticable (to most users), but its absence would distract or hinder users. Users always come first, and that sentence reminds me why I _have to_ master at least the basics of UI motion as a front-end dev.

---

## Conclusion

We’re done with [Svelte official tutorials on Transitions](https://svelte.dev/tutorial/transition)! 🎉

- Transition in Svelte is done by defining/importing a function and adding it to the `transition` OR `in` and `out` _directive_ in the element you’d like to animate.
- Common built-in transitions (`fade`, `slide`, etc), are provided out of the box in the `svelte/transition` module. They return regular CSS animations when run.
- You may also create your own custom transitions, either based on CSS or JS (ie. working with DOM elements). Common [easing styles](https://svelte.dev/examples#easing) are provided in the `svelte/easing` module to help you create or customize transitions.
- Helpers/functionalities for more specific use cases geared towards web UI needs are also available: “local”  and “deferred” transitions. These modules make it easier to work with motion in Svelte.
- In addition to the tutorials, [Svelte’s API docs page](https://svelte.dev/docs) has all the information you may need!
- I like that these tutorials are brief and practical, and the live sandbox is very helpful for me when I’m trying to understand how things work. I also learn various useful things in vanilla JS, CSS, and HTML along the way.

That’s it for now! Thanks for learning with me and... just keep _moving_.

{% youtube Q8w81AAK7to %}