Svelte.js 3 Reactive Statements & Declarations Tutorial

Learn reactivity in Svelte with reactive declarations, statements and conditional reactive statements.

We also cover reactive assignment and its importance.

Lesson Project

If you want to follow along with the examples in this lesson, you’ll need a Svelte app that was cloned with degit or scaffolded with Vite

If you already have an app from previous lessons, you can use that instead.

What are Reactive Statements & Declarations in Svelte?

Reactive statements and declarations can be bound to the markup like regular data, but can also have logic like functions. We use them to compose data from existing sources.

As an example, let’s say we allow the user to input their first and last name in two separate input fields. We want to display their full name in the markup so we use string interpolation to output each variable.

Example: src/App.svelte
<script>
  let firstName = ''
  let lastName = ''
</script>

<p>Full Name: { firstName } { lastName }</p>
<p>
  <label for="firstName">First Name: </label>
  <input id="firstName" type="text" bind:value={firstName}>
</p>
<p>
  <label for="lastName">Last Name: </label>
  <input id="lastName" type="text" bind:value={lastName}>
</p>

When we enter a first and last name in the browser, it shows in the first paragraph. So everything works as expected.

Now let’s say we want the first and last names to be combined into a full name. But if we do that, the data is no longer reactive and it won’t work.

Example: src/App.svelte
<script>
  let firstName = ''
  let lastName = ''

  let fullName = firstName + ' ' + lastName
</script>

<p>Full Name: { fullName }</p>
<p>
  <label for="firstName">First Name: </label>
  <input id="firstName" type="text" bind:value={firstName}>
</p>
<p>
  <label for="lastName">Last Name: </label>
  <input id="lastName" type="text" bind:value={lastName}>
</p>

If we enter first and last names in the browser, the full name doesn’t update.

The contents of the script block is executed only once when a component is loaded, so the first and last names are assigned to the full name when the component loads and the full name won’t be updated after that.

To illustrate this more clearly, let’s define default values for our first and last names.

Example: src/App.svelte
<script>
  let firstName = 'John'
  let lastName = 'Doe'

  let fullName = firstName + ' ' + lastName
</script>

<p>Full Name: { fullName }</p>
<p>
  <label for="firstName">First Name: </label>
  <input id="firstName" type="text" bind:value={firstName}>
</p>
<p>
  <label for="lastName">Last Name: </label>
  <input id="lastName" type="text" bind:value={lastName}>
</p>

If we try to change the first and last names, nothing happens because the full name was defined with “John” and “Doe” when the script section first loaded.

Reactive statements and declarations allow us to do things like this and still keep the data reactive.

How to use Reactive Declarations in Svelte

To define a reactive declaration, we use Svelte’s special $: assignment syntax, followed by the declaration name and a composing expression.

Syntax: reactive declaration
$: declaration_name = expression

tip While Javascript does use $: ( label ), it’s only in the context of iteration control (loops). Outside of a loop it doesn’t mean anything so Svelte decided to use it for reactive assignment.

To demonstrate, let’s use a reactive declaration to compute the full name from our earlier example.

Example: src/App.svelte
<script>
  let firstName = ''
  let lastName = ''

  $: fullName = firstName + ' ' + lastName
</script>

<p>Full Name: { fullName }</p>
<p>
  <label for="firstName">First Name: </label>
  <input id="firstName" type="text" bind:value={firstName}>
</p>
<p>
  <label for="lastName">Last Name: </label>
  <input id="lastName" type="text" bind:value={lastName}>
</p>

This time when we enter a first and last name in the browser, the full name updates as expected.

How to use Reactive Statements in Svelte

Reactive statements are part of Svelte’s reactivity system and uses the same $: assignment syntax. The difference is that we don’t declare a variable for the statement.

If it’s an inline statement, we write it directly and if there are multiple statements we write them in a code block.

Syntax: reactive statement
// single statements
$: statement

// multiple statements
$: {
  // code block
}

As an example, let’s create a reactive statement that greets the user by their first and last name. To show that the data is still reactive, we’ll add a button that changes the first and last names.

Example: src/App.svelte
<script>
  let firstName = 'John'
  let lastName = 'Doe'

  function changeName() {
    firstName = 'Jane'
    lastName = 'Roe'
  }

  $: {
    const greeting = `Hello there ${firstName} ${lastName}`
    console.log(greeting)
  }
</script>

<button on:click={changeName}>Change Name</button>

When we run the example and take a look in the Console tab of the browser’s developer tools, we’ll see the greeting with the default name.

If we then click on the button, another greeting with the new name will be logged to the console. So the data is still reactive.

How to create conditional Reactive Statements in Svelte

Svelte allows us to create conditional reactive statements by simply adding the $: before the conditional block.

Syntax: reactive conditional statement
$: if(condition) {
  // logic
}

As an example, let’s create a separate reactive statement that uses an if statement to check the first name, changing a title based on the result.

Example: src/App.svelte
<script>
  let title = 'Mr.'
  let firstName = 'John'
  let lastName = 'Doe'

  function changeName() {
    firstName = 'Jane'
    lastName = 'Roe'
  }

  $: if(firstName === 'Jane') {
    title = 'Ms.'
  }

  $: {
    const greeting = `Hello there ${title} ${firstName} ${lastName}`
    console.log(greeting)
  }
</script>

<button on:click={changeName}>Change Name</button>

If we run the example and take a look in the Console tab of the browser’s developer tools, we’ll see the greeting with the default title and name values.

When we click the button, the first and last names will change as we expect. But because firstName is a dependency in the reactive if statement, Svelte knows to run the if statement when it changes, changing the title if the condition proves true.

Reactive assignment system in Svelte

It’s important to note that the reactive system works based on assignment. That means when we’re working with objects or arrays, directly changing values won’t cause an update.

To demonstrate, let’s create a user array of objects and add a button that pushes a new user into the array when clicked.

Example: src/App.svelte
<script>
  let users = [
    { id: 1, name: 'John Doe' }
  ]

  function addName() {
    // push object into array
    users.push({ id: 2, name: 'Jane Roe' })
  }
</script>

<button on:click={addName}>Add name</button>

{#each users as user}
  <p>({user.id}) {user.name}</p>
{/each}

When we run the example and click on the button, nothing happens.

That’s because even though Svelte’s each loop is run reactively and should update the array, there’s no assignment and so Svelte doesn’t register the update.

So instead of pushing a new value to the array, we create a new array with the same name. Then we spread the current items (the existing user object) into it and add the new user’s object.

Example: src/App.svelte
<script>
  let users = [
    { id: 1, name: 'John Doe' }
  ]

  function addName() {
    // spread current items into array
    // and add the new user object
    users = [...users, { id: 2, name: 'Jane Roe' }]
  }
</script>

<button on:click={addName}>Add name</button>

{#each users as user}
  <p>({user.id}) {user.name}</p>
{/each}

This time when we click the button, the new user is added and shows in the list. Svelte could register the update because of the assignment.