Upcoming Course: Code Your Own Business w/ React + GraphQL!
We're live-coding on Twitch! Join us!

Building My First Svelte App: Thoughts and Impressions

Code Demo

There are always going to be new JavaScript libraries and frameworks that pop up. Sometimes it's easy to feel that we are in a new JS library fatigue mode. It is an amazing thing though since this means more innovation across all of the JavaScript land.

Svelte v3 (by Rich Harris) hit the scenes back in April and it took the dev world by storm. Everywhere you looked on social media, Svelte was being talked about.

I stayed away from trying out Svelte. Usually I'll dive head first immediately; this time I was a bit busy and thought I'd wait a bit. On yesterday's Twitch stream, I gave it a try on my Twitch channel.

My Main Impressions

The syntax is so clean!** **For writing your JavaScript and your styles, it just makes sense. It's as close to vanilla JavaScript as it gets.

The most complex part **(although not that complex) is the templating**. Vue's directives are easy to grasp. JSX is closer to JavaScript. Svelte's seems like a bit of a learning curve.

I like how components and props are handled. I like how you just have to update a variable and it updates. No worrying about things like setState().

I like how styles are automatically scoped. Haven't messed with trying to add Sass yet.

Essential Reading: Learn React from Scratch! (2019 Edition)

I still haven't gone in depth enough to judge overall. I'd really like to take Sapper, the Svelte framework, for a try.

Overall very clean and succinct!

Final Code and Demo

Here's the final CodeSandbox for this demo:

Benefits to Svelte

You may be asking why you would use Svelte over something more established like React, Vue, or Angular. This is exactly what I meant to find out in my first experiments.

  • Less code to write: Use HTML/CSS/JS without having to remember too much extra stuff
  • No Virtual DOM: Svelte compiles your code to tiny, framework-less vanilla JS — your app starts fast and stays fast
  • Reactive: Reactivity is built-in so you have to worry less about state management

This is all the code that is needed for a Hello World in Svelte:

<script>
    let name = 'world';
</script>

<h1>Hello {name}!</h1>

You might be thinking, well that's just JavaScript! You're right! The only thing in there that's a little different than vanilla JavaScript is Svelte's templating with name.

Svelte Starting Tutorial and Examples

The Svelte website has a great tutorial walkthrough that you can give a try.

There are also some great examples so you can get an idea of what certain apps look like:

I always like the approach of building an app after going through beginner tutorials. Let's start working on our tiny first app.

Building a Small Svelte App

The main things that I like to do when trying out a new library/framework is to build an app that:

  • Grabs data from an API
  • Show data in a list
  • Create an input box
  • Use that input box to run a search
  • Take new search data and update our view

It's a basic app that gives us access to see how the Svelte handles things like:

  • HTTP requests
  • Lifecycle methods
  • Templating - Displaying data
  • Templating - Looping over things
  • Templating - Conditionally showing things
  • State - Updating the data and view

Let's grab some data from the GitHub API and show that! Not the most advanced app, but it gets the job done while we are experimenting with Svelte for our first time.

GitHub API Endpoints

We'll be using the GitHub API to grab some users. The GitHub API is good because it doesn't require us to authenticate for small demo apps like the one we'll be building.

We'll also be using the API to search for GitHub users. These are our API endpoints:

You can click each of those links to see what the API will return in JSON.

I'm using the Chrome Extension called JSON Formatter to make the JSON look good in browser.

Starting Our Svelte App

Let's open up CodeSandbox and create a new Svelte app.

Once we click on a Svelte app, we can see the base Svelte app that has a few files. index.js is where everything gets bootstrapped and Rollup is used to compile our Svelte app to vanilla JavaScript.

Notice that there is only one dependency: Svelte.

Our index.js file is where our application gets bootstrapped

// index.js

import App from "./App.svelte";

const app = new App({
  target: document.body
});

export default app;

We can look inside of our App.svelte to see what a Svelte component looks like:

// App.svelte

<script>
    import Button from "./Button.svelte";
</script>

<style>
  main {
    font-family: sans-serif;
    text-align: center;
  }
</style>

<main>
    <h1>Hello CodeSandbox</h1>
    <h2>Start editing to see some magic happen!</h2>
    <Button />
</main>

A Svelte component consists of:

  • script: Where all of our JavaScript lives
  • style: All of our scoped styles live here
  • Template: Everything outside of a script or style tag will be treated as the template for this component

Unlike Vue, we don't need a <template> tag to tell Svelte where our template lives. Unlike React, we don't need a render() method.

Using Components

Svelte allows us to use components like this included Button component. We can import it as if it were a module and use it using <Button />.

Cleaning Up App.svelte

Let's clean up our app by deleting the Button.svelte and cleaning up the App.svelte. Here's our new App.svelte:

// App.svelte

<script>
</script>

<style>
</style>

<main>
</main>

Here's our new folder structure without the Button.svelte file:

Grabbing GitHub Users

Let's go and grab users using JavaScript's built-in fetch() since Svelte doesn't come with a built in HTTP library.

Let's create a function to go and grab data from the GitHub API at that URL from above. Here's our full App.svelte now:

// App.svelte

<script>
    /_*
   _ Grab users from GitHub
   */
  function getGitHubUsers() {
    fetch("https://api.github.com/users")
      .then(resp => resp.json())
      .then(data => {
        console.log(data);
        // do something with the users here
      });
  }
</script>

<style>
</style>

<main>
</main>

We have created a getGitHubUsers() function that will use fetch to get users. We have our function to go and grab the GitHub users, but we haven't called it just yet.

How do we get Svelte to call this function when the app starts up? Lifecycle methods!

Lifecycle Methods in Svelte

We have a function to grab users from GitHub. How do we use it when our application starts up? In React, we would use something like componentDidMount() or useEffect(). In Vue, we would use mounted(). Angular would use ngOnInit().

Svelte has lifecycle methods that we can import individually! For this case, we will import onMount and use our getGitHubUsers() function within that..

Our new App.svelte looks like this:

// App.svelte

<script>
  import { onMount } from "svelte";

    // run this when the app starts
  onMount(() => {
    getGitHubUsers();
  });

  /_*
   _ Grab users from GitHub
   */
  // code redacted for brevity
</script>

<style>
</style>

<main>
</main>

Now when we refresh our CodeSandbox browser, we can see all the users in the console.

Displaying Data in Svelte

Now that we are able to fetch this data, we need to store these users in a variable and display it.

We'll do the following:

  • Create a variable to hold the users
  • Update those users inside of our getGitHubUsers() method

Here's the new App.svelte:

// App.svelte

<script>
  import { onMount } from "svelte";

  // create a variable to store our users
  let users;

  // run this when the app starts
  // code redacted for brevity

  /_*
   _ Grab users from GitHub
   */
  function getGitHubUsers() {
    fetch("https://api.github.com/users")
      .then(resp => resp.json())
      .then(data => {
        // bind users to our users variable
        users = data;
      });
  }
</script>

<style>
</style>

<main>
  {users}
</main>

We've done three things here:

  1. Created a users variable with let users;
  2. Bound our GitHub data to this users variable with users = data
  3. Displayed the users with {users}

Now if you refresh the CodeSandbox browser, you'll see the data in the browser!

We can simplify our getGitHubUsers() function even further by removing the console.log():

// App.svelte

    /_*
   _ Grab users from GitHub
   */
  function getGitHubUsers() {
    fetch("https://api.github.com/users")
      .then(resp => resp.json())
      .then(data => (users = data));
  }

Now this data is just a bunch of JavaScript objects so it only displays as [object Object]. Let's start looping over this array so that we can show things.

Looping Over An Array in Svelte

To loop in Svelte, Svelte comes with some special template tags. Svelte comes with the each block to let us loop over data. Svelte also has support for if blocks, else/if blocks, and even await blocks.

Here's an example of an each block:

<ul>
    {#each cats as cat}
        <li>

            <a href="https://www.youtube.com/watch?v={cat.id}">
                {cat.name}
            </a>

        </li>
    {/each}
</ul>

Let's take the same syntax and use it for our own users:

// App.svelte

<main>

  {#if users}
  <ul>
    {#each users as user}
      <li>{user.login}</li>
    {/each}
  </ul>
  {/if}

</main>

Notice that we are also using an {#if block so that our users section doesn't show until we actually have users data. When our app starts, the users variable is set to undefined. Since Svelte can't loop over undefined, we have to tell Svelte to wait until we actually have an array to loop over.

We are looping over users and showing user.login since that's how the GitHub API stores a user's username.

Refresh CodeSandbox and you'll see the following list!

Using a Svelte Child Component

Let's take this a step further and create a child component for each user. We'll name this component User so that we can use it like so:

<User username="username-goes-here" avatar="avatar-goes-here" />

The first step to creating this new User component is to create a new User.svelte file:

// User.svelte

<script>
</script>

Right now, we have a blank Svelte component. We will pass it two props:

  • username
  • avatar

Each User component will be responsible for showing both the username and the avatar.

Passing Props to a Svelte Child Component

We have our child component, but how do we tell it that it will receive props. The Svelte docs shows that we can define props using export let propName

To tell our <User /> component that it will receive both username and avatar, we have to change our component to look like so:

// User.svelte

<script>
    export let username;
  export let avatar;
</script>

The next step is to display these in our template:

// User.svelte

<script>
  export let username;
  export let avatar;
</script>

<div class="user">
  <img src="{avatar}" alt="{username}'s Avatar" />
  <h3>{username}</h3>
</div>

Using our new component in App.svelte:, we'll need to import our User component and then use it inside of our each loop.

// App.svelte

<script>
  import { onMount } from "svelte";
  import User from "./User.svelte";

  // ... code redacted for brevity
</script>

<style>
</style>

<main>

  {#if users}
  <ul>
    {#each users as user}
      <li>


        <User username={user.login} avatar={user.avatar_url} />


      </li>
    {/each}
  </ul>
  {/if}

</main>

We have imported the User component and used it. We've also passed in our two props that we need here:

<User username={user.login} avatar={user.avatar_url} />

Our users will now show up with their images!

Some CSS Styling

Let's add some styles to our App.svelte and our User.svelte. The styles for each component are automatically scoped to that file so we'll need to adjust two different files.

Update your App.svelte to look like the following:

// App.svelte

<script>
    // ... redacted for brevity
</script>

<style>
  .user-list {
    display: flex;
    flex-flow: wrap;
    list-style: none;
    margin: 0;
    padding: 0;
  }

  .user-list li {
    width: 20%;
    padding: 10px;
  }
</style>

<main>

  {#if users}
  <ul class="user-list">
    {#each users as user}
      <li>
        <User username={user.login} avatar={user.avatar_url} />
      </li>
    {/each}
  </ul>
  {/if}

</main>

Notice that we've added a user-list class to our ul and also added to the style tag.

Next let's update our User.svelte to add some styles and CSS classes there. Remember that styles are scoped to each component meaning that styles won't bleed out of each component and affect the other components.

// User.svelte

<script>
  export let username;
  export let avatar;
</script>

<style>
  .user {
    padding: 5px;
    border: 1px solid #ddd;
    box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1);
    border-radius: 5px;
    text-align: center;
  }

  img {
    border-radius: 5px;
    max-width: 80px;
  }

  h3 {
    font-size: 16px;
    margin: 0;
  }
</style>

<div class="user">
  <img src="{avatar}" alt="{username}'s Avatar" />
  <h3>{username}</h3>
</div>

We've added a user class and some styles.

Our app should look like this now. Remember you may need to refresh the CodeSandbox browser because the updates don't automatically update for some frustrating reason.

Searching for Users

So far we've only been able to get data and show data. The next thing to look at when evaluating any JavaScript library or framework is to see how it handles events. We are going to create a new section of our app that allows us to search for specific GitHub users.

Let's create a new component and call it UserSearch.svelte. We'll start with our template:

// UserSearch.svelte

<script>
</script>

<style>
  .user-search {
    padding: 20px;
    border-radius: 10px;
    margin-bottom: 50px;
    background: #efefef;
  }

  h2 {
    margin: 0 0 15px;
  }
</style>

<div class="user-search">
  <h2>Search for Users</h2>

  <form>
    <input type="text" />
    <button>Search</button>
  </form>
</div>

We have some styles, a form, and an input. Import this new component into App.svelte and add it to the top of the template:

// App.svelte

<main>

  <UserSearch />

    // other stuff goes here

</main>

Now our app has added a new form:

Let's see how we can use this new form.

Binding Values to an Input in Svelte

The first thing we need to do is find a way to get information out of this input field. Svelte allows us to bind to an input using bind:value on an input. Here's an example:

<input bind:value={name}>

We'll create a new variable called usernameQuery and bind it in UserSearch.svelte:

// UserSearch.svelte

<script>
  let usernameQuery = "";
</script>

<style>
    // ... removed for brevity
</style>

<div class="user-search">
  <h2>Search for Users</h2>

  <form>
    <input type="text" bind:value={usernameQuery} />
    <button>Search</button>
  </form>

  {usernameQuery}
</div>

Notice how we have created a new variable called usernameQuery and also bound it to our input using bind:value={usernameQuery}. We've also added {usernameQuery} to the template just so we can see if the binding works.

Test out your new form! As you type, you should see the usernameQuery updated:

Handling an Event in Svelte

The next thing we need to handle is searching for a user on GitHub as soon as a user submits the form. To submit the form, the user can either click the Search button or press Enter when inside the input.

Handling a Form Submission

We'll bind an event in Svelte using on:click or in our case on:submit.

// UserSearch.svelte

<form on:submit={handleSubmit}>
  <input type="text" bind:value={usernameQuery} />
  <button>Search</button>
</form>

We've bound on:submit to use a handleSubmit function. Let's define that now. In the <script> section of UserSearch.svelte, we'll add our function.

Searching for GitHub Users

The code for our <script> will look like this:

// UserSearch.svelte

<script>
  let usernameQuery = "";
  let user;

  /_*
   _ Search for a user once our form is submitted
   */
  function handleSubmit(e) {
        e.preventDefault();

    fetch(`https://api.github.com/users/${usernameQuery}`)
      .then(resp => resp.json())
      .then(data => (user = data));
  }
</script>

We have a new user variable and are binding the information we get from GitHub to this user variable. We are also making sure that we use e.preventDefault() so that our HTML form doesn't try to reload the page when we submit the form.

Displaying User Data

Our next move is to show off this user that we just searched for. We have all the knowledge we need to display information. We also have a component ready to use for this specific purpose of showing a user.

Let's go and import our User component:

// UserSearch.svelte

<script>
  import User from "./User.svelte";

Now we can show this in the template! We'll conditionally show it since our user variable starts as undefined.

{#if user}
  <User username={user.login} avatar={user.avatar_url} />
{/if}

Try searching for your own GitHub username or you can use octocat:

Conclusion

Voila! We have a tiny Svelte app and have learned some of the Svelte basics!

Initial Thoughts on Svelte

It's still early and I will experiment more, but I'm liking what I'm seeing so far.

I don't believe I've gone far enough to really see the benefits of Svelte. I want to create another app with more data updating and reactivity.

Some big questions remain:

  • How are the 3rd party packages?
  • How is the open source ecosystem?
  • How will the developer experience be? There don't seem to be any Svelte DevTools yet.

There is a framework built on top of Svelte by the Svelte team called Sapper. I'll have to dig into that to see how much that framework adds. Things like server-side rendering and routing.

Overall, I'm liking what Svelte has to offer. The cleanness of the code, the ability to ship vanilla JavaScript, and the use of JS/HTML/CSS.

The things I'm not sure about are the lack of DevTools and once we build larger Svelte apps, how many 3rd party packages are there for things like graphs, modals, etc.

All the best to Svelte and team! I look forward to seeing what comes next.

Like this article? Follow @chrisoncode on Twitter