Introducing Svelte Attachments
Hey friends, the other day Svelte released a new feature named attachments. As you can read, attachments are functions that run when an element is mounted to the DOM. But they're actually a lot more. They're basically element level life cycle functions. And in the past, you might have used Svelte actions to do something similar, which is what attachments replace.
And attachments are really awesome because they let you attach some behavior to an element. For example, you might want to measure the mouse X and Y position inside an element. Well, you can make an attachment for that or maybe a link preview. So, when you hover your mouse over a link, it's going to show a preview using an iframe. The possibilities are endless.
In this video, I'm going to show you how attachments work, how they replace Svelte actions, and how you can use them in your project.
Animating in Svelte Before Attachments
So, let's start from the beginning. We're going to look at an example of integrating a third party JavaScript library such as the GSAP animation library in Svelte. Here I'm just importing GSAP from GSAP and then I'm creating this box.
Now we have a couple of options how we want to animate this box. The first method is going to be using onMount. So we know that the box exists and for this we can use document.query selector even though it's not the most reliable. And now we can say gap.to, we can pass it the box and we can pass our animation options.
Alternatively, we can use the bind directive to get a reference to the box. And this works the same way. Instead of onMount, we can also use an effect because effects run when the component mounts. But there is a downside to using effects.
Because you're using an effect, any reactive value you pass to the effect is going to rerun the effect when the value updates. And then to fix this problem you created for yourself, you have to use onTrack. As you can see in this example, it would have been much easier if you just used onMount.
The Problems with Svelte Actions
So let's talk about Svelte actions and their shortcomings. In the previous example, we used the onMount component level life cycle function. Now imagine instead of it being at the component level, you have an element level life cycle function and that is what Svelte actions are.
So action is just a basic function. It accepts an element and you can also pass it different parameters. But the way you use a Svelte action is using the use directive. So we can say use: and then we can pass our functions with the arguments that you want to pass to it. And this is really cool and one of my favorite features of Svelte because you can just attach random logic to individual elements.
But there are some downsides to Svelte actions. The first downside is that Svelte actions have an unusual syntax. As you can see, we have to understand that this method or whatever implicitly has an element passed to it, which is kind of confusing. The second downside is that the action itself has to be declared somewhere else. You also can't have inline actions. Svelte actions also aren't reactive by default. If the value of action changes or the state you passed in, it's not going to update unless you use an update function inside or the recent recommendation, an effect. Svelte actions also can't be conditionally applied. Neither can they be spread. So you can't create an object where you have a Svelte action and then spread it onto an element or component. Which leads us to the last part. You can't use Svelte actions with components. And these are the issues that Svelte attachments aim to fix.
How Attachments Solve These Problems
Let's see how Svelte attachments improve the situation. By using the same example, we can already see a more consistent API with attachments by using the @ symbol followed by the keyword attach. And as you can see, here is the first huge win of Svelte attachments: we can define them inline, which is really great when you want to do some quick attachment without that ceremony of creating a function and so on. This is really great for things like canvas and SVG.
Let's use a function instead. As you can see, Svelte attachments are just regular functions. Attachments run when the element is mounted. And you can also run a cleanup function after they're gone.
We can do the same animation example as before using GSAP and passing it the element reference. But what if we want to pass the options ourselves? Well, in that case, we can just use a regular function and return the attachment. And I don't want to give you Redux flashbacks, but this pattern is also called a thunk, which is something I learned recently. And basically a thunk is just a function returned from another function which holds some expression that's evaluated later but that's not important. Of course, same with Svelte actions we can have multiple attachments.
So let's import draggable from gsap/draggable and then we can register this plugin with GSAP. Then we can simply create a drag attachment which we pass some options to. We get a reference to the element and then we can create a draggable element with GSAP which is really easy. And just like that, the element is now draggable. How beautiful is that?
Reactivity in Svelte Attachments
Let's look at an example how we can pass reactive state to attachments. Here I'm using this scramble text plugin from gsap/scrambleTextPlugin. After we register it, we can create this scramble attachment. One thing that you should keep in mind is that attachments are basically wrapped inside of an effect. So if you pass some reactive state inside of it, it's going to update this attachment when the value updates. But if you want, you can untrack this value. And I'm only telling you this so you're aware because in most situations, this is exactly the type of behavior that you want.
So in this example, we declared a reactive piece of state named text. And now we can bind the value of this text to the input. And now each time the value of text updates it's going to rerun the scramble attachment because we're reading the reactive value inside of it.
So let's update the input. As you can see everything is reactive as expected.
Advanced Patterns and Composability
Let me show you one last cool thing including types because basically these are just functions. We can do whatever we want. So we can create something like a createAnimation function where we pass the GSAP options. Then we can create an animation variable and then we can return the attachment and any other method that we want.
So now we can declare an animation by saying const animation = createAnimation with the properties that we want to pass. Now we can simply register the animation attachment by saying animation.to. And now that we have a reference to the animation itself, we can say animation.play. And this is a really fun example. As you can see, there is no limit to what you can do. And I hope this at least inspires you.
Recap and Documentation
All right, so let's do a quick recap. Attachments have a way simpler and improved syntax. They can be declared anywhere. They can also be used in line and they're reactive by default. And one thing I haven't shown you, but you can do it, you can conditionally apply attachments and they can also be spread. And the best part is that you can also use them on components. Of course, you can find more of these examples in the documentation.
So, here they show you how you can use things like nested effects where you have this canvas so you can trigger this update when the value of color updates and things I haven't shown you like spreading props. So, we can see we can create attachments programmatically so you can easily create attachments and spread them.
As always, thank you for watching and I'll catch you in the next one. Peace.