All you need to know to start writing Svelte Single File Components
Tags: javascript, svelte, webdev
Published: 2020-01-17 05:41:22

This article is Part II of my first three posts about Svelte. In my opinion, the principle to have a JavaScript [(UI) framework without a framework](https://svelte.dev/blog/frameworks-without-the-framework) is the most promising for the future of frontend development. I'm looking forward writing about Svelte. Part I discusses how to create a [statically generated website with Svelte and Sapper](https://dev.to/vannsl/statically-generated-website-with-svelte-and-sapper-5bi7). Part III shows [how to use TailwindCSS with Svelte and Sapper](https://dev.to/vannsl/configuring-tailwindcss-for-sapper-58jm).

*Version:*
Svelte: 3.16.7

## Introduction

Svelte is a modern framework to create cybernetically enhanced web apps. Without loading the whole library on the client, it does all of the work in the compile step. There is a lot more to tell about Svelte, but today we'll only talk about how to create things with Svelte.

**This article focuses on writing Svelte Single File Components.** It describes how to:

1. [structure a svelte file](#chapter-1)
  - [create data attributes](#chapter-2)
  - [render markup conditionally](#chapter-3)
  - [handle events](#chapter-4)
1. [compose components](#chapter-5)
  - [pass properties to child components](#chapter-6)
  - [use slots](#chapter-7)
1. [continue with Svelte](#chapter-8)

<a name="chapter-1"></a>
## A .svelte Single File Component (SFC)

Svelte SFCs look very similar to Vue or with other words: like HTML, JavaScript, and CSS. The usual differs slightly from Vue SFCs:

A .svelte SFC starts with the **`<script>` block**. It contains the logic of the SFC. It can import child components and export data attributes and properties.

It is followed by the **`<style>` block**. It contains the CSS for this component. Compared to other component-based frameworks, the style it automatically `scoped` to this component without adding a keyword for it. 

> Styles are scoped to the component by default. For global styles add the keyword: `<style global></style>`.

The part of the HTML is surprisingly not wrapped inside in a `<template>` block. There is also no need to wrap all of the HTML tags within one surrounding tag. It's important: there is **no `<template>` block**. HTML can just be added to the file.

An example .svelte SFC looks like this:

```html
<!-- component.svelte -->
<script>
  // nothing to do here. This block can be removed.
</script>

<style>
  h1 {
    font-size: 42px;
  }

  p {
    font-size: 14px;
  }
</style>

<h1>Hello World!</h1>
<p>I am a Demo.</p>
```

By not wrapping the HTML in surrounding tags, there are a few things different from other component-based frameworks:

- grid styling might get simpler by having more freedom
- besides passing properties, it is not possible to add other attributes like `class=""` to a child component.

<a name="chapter-2"></a>
### Data attributes

The template language of Svelte is Angular/Vue alike. Like in those frameworks, there are similarities to [Handlebars](https://handlebarsjs.com/). To use variables within the template, wrap them in curly braces: `{VARIABLE}`.

```html
<script>
  const title = "World";
</script>

<style>
  h1 {
    font-size: 42px;
  }

  p {
    font-size: 14px;
  }
</style>

<h1>Hello {title}!</h1>
<p>I am a Demo.</p>
```

> Although I would consider it as a bad idea to add HTML via variables in the markup, it's possible by writing `<h1>Hello {@html title}</h1>`.

Variables can also be used to bind dynamic values to HTML attributes. E.g. an anchor link with a href variable looks like this:

```html
<a href={href} target="_blank" rel="noopener">
  Open Link
</a>
```

> A common mistake at the beginning when using variables for HTML attributes could be to add quotes for the variables. It's `href={href}` and not `href="{href}"`.

A nice feature is to use [shorthand attributes](https://svelte.dev/tutorial/dynamic-attributes). When the name of the variable equals the name of the attribute, it's enough to add only the attribute in curly braces:

```html
<a {href} target="_blank" rel="noopener">
  Open Link
</a>
```

> Shorthand attributes can reduce redundant code. For example, it's possible to use `{href}` for `href={href}`.

It's even possible to spread an object to add several attributes:

```html
<script>
  const link = {
    href: "some src",
    target: "_blank",
    rel: "noopener"
  }
</script>

<a {...link}>
<!-- will be compiled to: <a href="some src" target="_blank" rel="noopener">-->
  Open Link
</a>
```

<a name="chapter-3"></a>
### Conditional rendering

Compared to other frameworks, `if` and `else` blocks are not implemented with directives. For [conditional rendering in Vue](https://vuejs.org/v2/guide/conditional.html) one would write: `<p v-if="true">`. For [conditional rendering in Svelte](https://svelte.dev/docs#if) one can achieve that by adding pure `if` blocks, wrapped in curly braces.

```html
{#if Math.random() > 0.5}
  <p>I like Svelte.</p>
{:else}
  <p>I don't like Svelte.</p>
{/if}
```

> For conditional rendering, `if-else` blocks can be written in curly braces. `Else` blocks are optional. `#` opens a block, `:` indicates a block continuation tag and `/` closes the block.

<a name="chapter-4"></a>
### Event Handler

Before the era of UI frameworks, developers used Vanilla JavaScript to add logic and behavior onto websites. [Onclick](https://www.w3schools.com/jsref/event_onclick.asp) handler provided the functionality to add callbacks to HTML elements, as soon as users clicked on them. In Svelte, event handlers are added to DOM elements by using the [element directive `on:`](https://svelte.dev/docs#on_element_event). It's possible to either pass a function as reference or write an inline function.

> Use `on:` to add event handlers on DOM elements.

A few examples to get a feeling for event handlers:

```html
<script>
  let counter = 1;

  function logout() {
    // ... log user out
  }

  function toggleTooltip() {
    // ... show or hide tooltip
  }
</script>

<button on:click={logout}>
  Logout
</button>

<div on:mouseover={toggleTooltip}>
  Info
</div>

<button on:click="{() => a += 1}">
<!-- you can pass the event as property: -->
<!-- <button on:click|preventDefault="{(e) => /* do something with the event e */}"> -->
  a is {a}.
</button>
```

Let's talk about how to compose components next.

<a name="chapter-5"></a>
## Composing Components

Child Components can be imported in the `<script>` block. They don't have to be registered any further.

```html
<script>
  import GridItem from '../components/GridItem.svelte';
</script>
```

The component can be added to the template like other HTML tags.

```html
<GridItem></GridItem>
<!-- or <GridItem /> -->
```

> Child components are written in CamelCase and imported in the `<script>` block.

The names of the components are case sensitive. It is recommended to use PascalCase for the names. The advantage of that is that it is possible to use _Header_, _Footer_ and other already taken tag names as names for the Svelte components. This is different from other frameworks where names like _TheHeader_  or _TheFooter_ are a workaround, although also making clear that these components should also only be used once within the page template.

<a name="chapter-6"></a>
### Passing properties

Properties can be passed with curly braces `{}`to the child components. Children can access the properties by exporting them. While to declare data attributes the syntax is `[let/const] variable = 'abc';`, the syntax for accessing passed properties is `export let variable;`.

```html
<!-- Parent.svelte -->
<script>
  import Child from '../components/Child.svelte';
</script>

<Child title="World!"></Child>

<!-- Child.svelte -->
<script>
  export let title;
</script>

<h1>Hello {title}</h1>
```

An optional **default value** can be added:

```html
<!-- Child.svelte -->
<script>
  export let title = "my dear friend.";
</script>

<h1>Hello {title}</h1>
```

> Use `<Child></Child>` or `<Child />` for nesting components without using slots.

<a name="chapter-7"></a>
### Use Slots

Now, it is time to create a simple Grid with GridItems slots that can be added by using the tag `<slot></slot>`. Please be aware of the simplicity of the implementation of this grid, which only allows two columns per row. [@vaheqelyan](https://github.com/vaheqelyan) implemented a much more complex version of a [Svelte-Grid](https://svelte-grid.now.sh/).

```html
<!-- Grid.svelte -->
<style>
  .section {
    display: flex;
    flex: flex-wrap;
  }
</style>

<section>
  <slot></slot>
</section>
```

To use several slots within one component, append the attribute `name=` to create **named slots**. Named slots and unnamed slots can be combined.

```html
<!-- GridItem.svelte -->
<style>
  .div {
    width: 50%;
  }
</style>

<div>
  <slot name="title"></slot>
  <hr>
  <slot name="content"></slot>
  <slot></slot>
  <!-- or <slot /> -->
</div>
```

It is a powerful way to create complex compositions of components. In the following we'll see a whole Grid example:

```html
<!-- index.svelte -->
<script>
  import Grid from '../components/Grid.svelte';
  import GridItem from '../components/GridItem.svelte';

  let title = 'World!";
</script>

<h1>Hello {title}</h1>

<Grid>
  <GridItem>
    <h2 slot="title">I will be rendered within the named slot title.</h2>
    <p slot="content">I will be rendered within the named slot.</h2>
    <p>I will be rendered within the unnamed slot.</p>
  </GridItem>
  <GridItem>
    <h2 slot="title">I only have a headline, nothing else.</h2>
  </GridItem>
</Grid>
```

> To add components, data, properties, etc. in Svelte, they only have to be imported or declared in the `<script>` block. There is no need to register them any further.

<a name="chapter-8"></a>
## Next steps

🤩 Prepared with this knowledge, implement your first basic Svelte Single File Component 🤩

Small static pages often don't need more functionality. To strengthen the knowledge, I recommend using 1h to go through the official [tutorial](https://svelte.dev/tutorial/basics).

There is more to learn. Svelte offers [lifecycle hooks](https://svelte.dev/tutorial/onmount), [bindings](https://svelte.dev/tutorial/text-inputs), [stores](https://svelte.dev/tutorial/writable-stores), [transitions](https://svelte.dev/tutorial/transition) and much more to create more complex applications. Keep on learning 👨‍🎓👩‍🎓