This article is all about using directives in Svelte. We'll go over how they work and how you can use them in your projects.
In my last article, I write an introduction to Svelte, covering its reactivity and basic features. In this article, I will dive into directives in Svelte.
In Svelte, directives are special attributes that change how a DOM element works. Directives start with a :
character. For example, on:click
directive is used to handle click events on an element. What I love about Svelte is how it helps you make your app interactive without needing complex event listeners and state management.
Let’s take a look at the on
directive and how we can listen and handle DOM elements with it. Let's say we want to bind the handleClick
method to our button element. We can do this by adding the on:click
directive to the button element and passing in the handleClick
method as the JavaScript expression. For example:
<script>
function handleClick() {
alert('Click has been handled');
}
</script>
<button on:click="{handleClick}">Click Me!</button>
This will bind the handleClick
method to the click
event of the button element so that when the button is clicked, the handleClick
method will be called.
Handlers can also be declared inline, so instead of calling our handleClick
function, we can directly call alert
inline like this.
<script>
function handleClick() {
alert('Click has been handled');
}
</script>
<button on:click="{() => alert('Click has been handled')}">Click Me!</button>
There are also modifiers in directives which are special postfixes that can be added to directives in Svelte. They are used to change the behavior of a directive.
on:eventname|modifiers={handler}
For example, let's say we want to prevent the default behavior of forms reloading when they submit. We can use preventDefault inside a modifier of the submit directive.
<script>
function handleSubmit() {
// Handle form submission
}
</script>
<form on:submit|preventDefault="{handleSubmit}">
<!-- Form fields go here -->
<button type="submit">Submit</button>
</form>
Modifiers can add extra functionality to directives. Let’s take a look at the self
modifier for example.
The self
modifier is used to specify that an event listener should only be triggered if the event occurred on the element itself, not on any of its children. In the code example below, we have a green div element with a nested red div. When the green div is clicked, the handleClick
method is called and an alert is shown.
However, when the red div is clicked, the handleClick
method is not called. This is because the self
modifier was used so the event listener only listens to events on the element itself, and not on its children.
<script>
function handleClick(string) {
alert(string);
}
</script>
<button on:click="{() => {alert('Click has been handled')}}">Click Me!</button>
<div
on:click|self="{() => {alert('Our green div was clicked!')}}"
class="greenDiv"
>
You can click the green.
<div class="redDiv">You can't click the red</div>
</div>
<style>
.greenDiv {
background: LawnGreen;
padding: 20px;
}
.redDiv {
background: OrangeRed;
padding: 20px;
}
</style>
Here are the available modifiers from Svelte docs .
The following modifiers are available:
preventDefault
— calls event.preventDefault()
before running the handlerstopPropagation
— calls event.stopPropagation()
, preventing the event from reaching the next elementstopImmediatePropagation
- calls event.stopImmediatePropagation()
, preventing other listeners of the same event from being fired.passive
— improves scrolling performance on touch/wheel events (Svelte will add it automatically where it's safe to do so)nonpassive
— explicitly set passive: false
capture
— fires the handler during the capture phase instead of the bubbling phaseonce
— remove the handler after the first time it runsself
— only trigger handler if event.target
is the element itselftrusted
— only trigger handler if event.isTrusted
is true
. I.e. if the event is triggered by a user action.The bind
directive is used to create a two-way binding between a variable and an element. This means that when the variable changes, the element will update, and when the element changes, the variable will update. For example, let's say we have an input element and we want to bind its value to a variable called name
. We can do this by adding the bind:value
directive to the input element and setting its value to name
. For example:
<script>
let name = '';
</script>
<input bind:value="{name}" />
This will create a two-way binding between the name
variable and the value of the input element. When the user types in the input, the name
variable will update, and when the name
variable changes, the input's value will update.
The bind
directive can also be used with other properties such as checked
for checkboxes and class
for classes. For example:
<script>
let isChecked = false;
</script>
<input type="checkbox" bind:checked="{isChecked}" />
<div class="{isChecked ? 'checked' : ''}">Checkbox is {isChecked ? 'checked' : 'unchecked'}</div>
This will create a two-way binding between the isChecked
variable and the checkbox's checked
property. When the checkbox is checked or unchecked, the isChecked
variable will update, and when the isChecked
variable changes, the checkbox's checked property will update.
The bind
directive is a powerful feature of Svelte that makes it easy to create interactive applications with minimal code.
Here are some examples of how you can use the bind method to manage form states more effectively.
// binding a select element
<select multiple bind:value={fillings}>
<option value="Rice">Rice</option>
<option value="Beans">Beans</option>
<option value="Cheese">Cheese</option>
<option value="Guac (extra)">Guac (extra)</option>
</select>
// binding a detail element
<details bind:open={isOpen}>
<summary>Details</summary>
<p>Something small enough to escape casual notice.</p>
</details>
You can check out more examples of binding elements here. Binding in Svelte .
The style directive is a really helpful tool in Svelte. To use it, you add an attribute to an element in the format style:property={value}
. The property part is the name of a CSS property and the value is what you want to set it to. Style directives are great because you can set individual properties without worrying about the whole CSS string.
<div
style:position="absolute"
style:top={position === 'absolute' ? '20px' : null}
style:pointer-events={pointerEvents ? null : 'none'}
>
</div>
A common strategy for writing dynamic styles in Svelte is to apply the styles directly as an attribute. For example, you can make a box move around the screen with some events. Take a look at the example below.
<script>
let mPosition = { x: 0, y: 0 };
function handleMouseMove(e){
mPosition.x = event.clientX / 10;
mPosition.y = event.clientY / 10;
}
$:console.log(mPosition)
</script>
<div on:mousemove={handleMouseMove} class='container'>
<div class="box" style="left: {mPosition.x}%; top: {mPosition.y}%" ></div>
</div>
<style>
.container{
width:100%;
height:100vh;
}
.box {
height: 80px;
width: 80px;
background: pink;
position: absolute;
}
</style>
In this example, we use the on:mousemove directive to call the handleMouseMove function whenever the mouse moves over the div element. Inside handleMouseMove, we update the x
and y
variables with the current mouse position. This works well but in Svelte we can use style directives to get the same behavior.
<script>
// ...
</script>
<div on:mousemove={handleMouseEvent} class='container'>
<div class="box" style:left="{mPosition.x}%" style:top="{mPosition.y}%"></div>
</div>
<style>
// ...
</style>
You can use style directives with any CSS property, including CSS custom property definitions.
<div style:--bg="red" class="box"></div>
<div style:--bg="green" class="box"></div>
<div style:--bg="orange" class="box"></div>
<style>
.box{
width:100px;
aspect-ratio:1/1;
background:var(--bg);
}
</style>
You can check out more about style directives here in the Official documentation .
Svelte also has directives that apply to the whole component rather than a specific element within it. To declare these directives, use the export
keyword in the component's script tag. For example, suppose we have a component called Button
that we want a user to click. We can make a clickable
directive for the component like this:
// Button.svelte
<script>
export let handleClick;
function handleClickWrapper(event) {
event.preventDefault();
handleClick(event);
}
</script>
<button on:click="{handleClickWrapper}"><slot /></button>
We made a function called handleClickWrapper
that stops the button from doing its usual thing when clicked, and instead runs the handleClick
function that we made in the component's script tag. Then we added the clickable
thing to the button element, which makes the button run the handleClickWrapper
function when it's clicked.
Now we can use the Button
in our app and give it a handleClick
function as a prop.
// app.svelte
<script>
import Button from './Button.svelte';
function handleClick(event) {
alert('Button clicked!');
}
</script>
<Button handleClick="{handleClick}">Click Me!</Button>
This will create a button that displays "Click Me!" and calls the handleClick
function when clicked.
Component-level directives are a powerful feature of Svelte that allows you to create reusable components with custom behavior.
Another example is that let’s say you are building a UI library with Svelte and you want to allow customizations. By using component-level directives, you can also pass styles as props to components for the purposes of theming, using CSS custom properties.
Svelte's implementation is essentially syntactic sugar for adding a wrapper element. For example,
// You can do this
<Slider bind:value min={0} --rail-color="black" --track-color="rgb(0, 0, 255)" />
// instead of this
<div style="display: contents; --rail-color: black; --track-color: rgb(0, 0, 255)">
<Slider bind:value min={0} max={100} />
</div>
<!-- Slider.svelte -->
<style>
.potato-slider-rail {
background-color: var(--rail-color, var(--theme-color, 'purple'));
}
</style>
Thank you for reading this article on directives in Svelte. I hope you found it informative and helpful. Make sure you read more about directives in the official docs .
Join my web development newsletter to receive the latest updates, tips, and trends directly in your inbox.
Get ready for a daily dose of Svelte coding fun as we count down to Christmas. Join me on this festive coding journey and let's celebrate the holiday season together!
A useful guide on how to use Stores and state management in Svelte
Slots, named slots, and slot props, the article also covers slots to create even more dynamic and flexible components in Svelte.