Understanding Svelte – The (very) basics

Understanding Svelte – The (very) basics

I have to admit, Svelte caught my attention.

It takes a totally different approach than other JavaScript UI libraries or frameworks for keeping the UI up-to-date with changes triggered by data changes or user interactions. Instead of re-rendering the appropriate segments of the UI at runtime, it prepares the work at build time – Svelte is a compiler.

If you're intrigued –as I was– go and have a look at the Svelte home page. There's also an outstanding REPL where you can dive right in and play around with some code. I'll put some more links at the bottom of this post for further where you can learn more.

You can also stay here for a few more minutes, and read about how I'm learning Svelte. This is just the first, short post in the series I'm planning to write as I'm learning what seems like a fascinating library. I think it's gonna be educational for you, too, as I've probably made (and will make) the same errors other people would make.

Component-focused

Components are what make Svelte is all about. That makes a ton of sense, of course, and doesn't surprise someone coming from another view library like React. However, it was a bit of a mind shift for me coming from Ember.js, a full-fledged SPA framework.

Also, all pieces that make up a component –the JavaScript, the styles, and the template– is placed in one single file with a .svelte extension.

I decided to build a relatively simple "app" as my first learning example that can gradually be extended in lots of ways to understand other bits of Svelte.

What I came up with is a crypto card that at first only displays the current price of a crypto currency. Later, I'll add historical prices and price changes, the possibility to update the current price, add other currencies, and so on.

So the first milestone is just to have the real price displayed:

Component props

I created a file called CryptoCard.svelte and pasted in the following:

// src/CryptoCard.svelte
<div class="card">
  <label>BTC</label>
  <div class="icon-holder">
    <IconRefresh fill="#CBD5E0" stroke="#CBD5E0" strokeWidth="0.1"/>
  </div>
  <span>$10,209</span>
</div>

Let's see the `IconRefresh` component:

// src/IconRefresh.svelte
<script>
  export let fill;
  export let stroke;
  export let strokeWidth;
</script>

<svg viewBox="0 0 24 24"
  xmlns="http://www.w3.org/2000/svg"
  fill="{fill}"
  stroke="{stroke}"
  stroke-width={strokeWidth}
>
  <path d="M8.52 7.11a5.98 5.98 0 018.98 2.5 1 1 0 11-1.83.8 4 4 0 00-5.7-1.86l.74.74A1 1 0 0110 11H7a1 1 0 01-1-1V7a1 1 0 011.7-.7zm5.51 8.34l-.74-.74A1 1 0 0114 13h3a1 1 0 011 1v3a1 1 0 01-1.7.7l-.82-.81A5.98 5.98 0 016.5 14.4a1 1 0 111.83-.8 4 4 0 005.7 1.85z"/>
</svg>

The props of the component that can be passed in from the outside need to be exported. Here, all of fill, stroke and strokeWidth are such props. When CryptoCard calls IconRefresh, it passes in all of these.

We can define default values for component arguments just by assigning them a value at definition time:

// src/IconRefresh.svelte
<script>
  export let fill;
  export let stroke;
  export let strokeWidth = 1;
</script>

strokeWidth now has a default value of 1 which can be overridden by passing it in, like in the above example.

Back in our code, we want to  be able to use IconRefresh so we need to import it:

// src/CryptoCard.svelte
<script>
  import IconRefresh from './IconRefresh.svelte';
</script>

<div class="card">
  <label>BTC</label>
  <div class="icon-holder">
    <IconRefresh fill="#CBD5E0" stroke="#CBD5E0" strokeWidth="0.1"/>
  </div>
  <span>$10,209</span>
</div>

Notice how we wrapped the JavaScript import in a <script> tag. All of the JavaScript code in our components will live inside it.

CSS

The card doesn't look anything like our original design so we need to add the necessary styles. They need to be placed inside <style> tags:

// src/CryptoCard.svelte
<script>
  import IconRefresh from './IconRefresh.svelte';
</script>

<style>
  .card {
    display: flex;
    flex-direction: row;
    justify-content: flex-start;
    height: 4rem;
    width: 16rem;
    background-color: #5A67D8;
    align-items: center;
    padding-left: .8rem;
    padding-right: .8rem;
  }

  label {
    color: #F7FAFC;
    font-size: 1.6rem;
  }

  .icon-holder {
    height: 24px;
    width: 24px;
    margin-left: auto;
    cursor: pointer;
  }

  span {
    font-size: 1.2rem;
    color: #F7FAFC;
  }
</style>

<div class="card">
  <label>BTC</label>
  <div class="icon-holder">
    <IconRefresh fill="#CBD5E0" stroke="#CBD5E0" />
  </div>
  <span>$10,209</span>
</div>

That's more like it! It's important to keep in mind that styles in a Svelte component are local to that component and thus don't leak. Svelte achieves this by auto-generating class names and applying it both to the rules and the elements they apply to:

We have now recreated the original small crypto tab.

It doesn't even have a real price, though, so we'll make it so in the next post and learn a thing or two about reactivity in Svelte.

In the meantime, some Svelte links: