Element Directives

In this module, we will go over a couple different element directives and events we have at our disposal with Svelte, and how to use them.
Table of Contents
Element DirectivesView the code for this module.

In the last module on Svelte’s reactivity, we used the on: directive to listen for a click event. That may have been a little foreign to you, as every framework has its own way of controlling an elements behavior. In this module, we will go over a couple different element directives and events we have at our disposal with Svelte, and how to use them.

Let’s start off with the on directive, which you will find yourself using a lot. The on directive is used to listen to DOM events. To use it, you say on followed by a : and the event name.

I’ve added a button and a function called handleClick. We want to call this handleClick method anytime the button is clicked. We can listen for this click event using on:click, passing in our handleClick method within single curly braces like this.

<script>
  function handleClick() {
    alert('Click has been handled');
  }
</script>
 
<button on:click="{handleClick}">Click Me!</button>

Now, if you test this in the browser, clicking the button will call the handleClick function, and you will see the alert. Now, what if we want to pass a string into our method to be logged? For example, let’s pass our string in as a parameter and log that parameter instead.

<script>
  function handleClick(string) {
    alert(string);
  }
</script>
 
<button on:click="{handleClick('Click has been handled')}">Click Me!</button>

If you test this in the browser, you’ll see that the alert shows right away, even though the button hasn’t been clicked. This is because the handleClick method is being automatically invoked by these parenthesis. What we should do instead is create an inline function that we are not invoking, so it will not run until we click the button. Then, within this function we can invoke handleString.

<script>
  function handleClick(string) {
    alert(string);
  }
</script>
 
<button on:click="{()=>{handleClick('Click has been handled')}}">
  Click Me!
</button>

Now, if you were to test this again, you won’t see the alert until the button is clicked. Handlers can also be declared inline, so instead of calling our handleClick function, we can directly call alert inline like this.

<script>
  function handleClick(string) {
    alert(string);
  }
</script>
 
<button on:click="{() => alert('Click has been handled')}">Click Me!</button>

We can even add one or more modifiers to DOM events using the vertical-line | character by placing this before each modifier name. For instance, let’s add a green <div>, and place a red <div> within it. Now, to our outer green <div>, let's once again call our handleClick function which will alert when it is clicked. If you test this out, you’ll notice that we see the alert when the green <div> is clicked, but also when the red child <div> is clicked. We can use the self modifier to only alert when the green <div> itself is clicked, but not any of its children. To our outer div where we listen for the click event, we can add the vertical line character followed by the self modifier like this:

<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>

Now, clicking the red child <div> will not alert, only clicking the green parent <div> itself will. You are not limited to using a single modifier. You can chain multiple modifiers together by just adding another | followed by the next modifier like this:

<script>
  function handleClick(string) {
    alert(string);
  }
</script>
 
<button on:click="{() => {alert('Click has been handled')}}">Click Me!</button>
<div
  on:click|self|once="{() => {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>

Now it will only alert if we click the green parent <div>, but only the first it is clicked. If we check out the Svelte documentation under Element Directives, you can view a list of available modifiers and what they do.

I also want to make sure I point out that the on directive can be used with any DOM events, not just clicks. Let’s remove our event modifiers and change this on directive to say on:mousemove instead of on:click. Let’s continue to call the handleClick function. The on directive provides you with the event object as an argument of your handler, so let’s pass in event and instead of alerting, log it. The updated code should look like this:

<script>
  function handleClick(event) {
    console.log(event);
  }
</script>
 
<button on:click="{() => {alert('Click has been handled')}}">Click Me!</button>
<div on:mousemove="{handleClick}" 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>

Now every time the mouse is moved within the green div, the mouse event will be logged in the console.

Typically, data flows down stream, from parent to child, but oftentimes we need to send data the opposite direction, from child to parent. For example, let’s look at the following code:

<script>
  let searchedValue = '';
  function setSearchedValue() {
    searchedValue = document.getElementById('myText').value;
  }
</script>
 
<div>{searchedValue}</div>
<input on:keypress="{setSearchedValue}" type="text" id="myText" value="" />

Here we have an <input>, and the on directive is being used to listen for the keypress event so that we can call our setSearchedValue method any time the input’s value changes. This function just sets the value of our searchedValue variable to the value entered in the input. If you were to test this in the browser, you would see that as you type in the input, searchedValue is updated. While this achieves our goal, Svelte provides us with a much simpler way of doing this using the bind directive. We use this directive by saying bind: followed by the property we want to bind. Let’s update this example to use it. We can delete our setSearchedValue function and no longer need to listen for the keypress event. Now, we can replace the input’s value with bind:value={searchedValue}.

<script>
  let searchedValue = '';
</script>
 
<div>{searchedValue}</div>
<input type="text" id="myText" bind:value="{searchedValue}" />

The value of our input is now bound with searchedValue, so anytime our input changes, searchedValue will as well, and vice versa. We could also, for instance, bind a value to whether or not a checkbox is checked. To do that, we would add a checkbox with checked as our bound property:

<script>
  let name = '';
  let checked = false;
</script>
 
<p>{name}</p>
<p>{checked}</p>
<input type="text" bind:value="{name}" />
<input type="checkbox" bind:checked="{checked}" />

Here, we’ve once again created a new variable, checked, and its value will start off as false. Now if we add another input, this time with type 'checkbox', we can bind the value of checked to this input by saying bind:checked={checked}. Now, our value checked is bound to whether our not our checkbox is checked. In cases like this, where property name matches the variable name, we can use a shorthand. Instead of writing it how we currently have it, we can instead write bind:checked.

Now in this module I just scratched the surface of element directives. In future videos we will dive a bit deeper into both the on: and bind: directives when it comes to creating custom events and binding data between components. We’ll also go over the animation and transition directives. The other element directives are not quite as common, so I won’t be covering them in this course, but they are all listed in the Svelte documentation under element directives if you’d like to check them out yourself.

Now that we understand how to handle our DOM events and bind values, let’s learn how to work with conditionals and loops in the next module.