DEV Community

Cover image for All you need to know to start writing Svelte Single File Components
Vannsl
Vannsl

Posted on • Updated on

All you need to know to start writing Svelte Single File Components

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 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. Part III shows how to use TailwindCSS with Svelte and Sapper.

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
  2. compose components
  3. continue with Svelte

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:

<!-- 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>
Enter fullscreen mode Exit fullscreen mode

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.

Data attributes

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

<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>
Enter fullscreen mode Exit fullscreen mode

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:

<a href={href} target="_blank" rel="noopener">
  Open Link
</a>
Enter fullscreen mode Exit fullscreen mode

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. When the name of the variable equals the name of the attribute, it's enough to add only the attribute in curly braces:

<a {href} target="_blank" rel="noopener">
  Open Link
</a>
Enter fullscreen mode Exit fullscreen mode

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:

<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>
Enter fullscreen mode Exit fullscreen mode

Conditional rendering

Compared to other frameworks, if and else blocks are not implemented with directives. For conditional rendering in Vue one would write: <p v-if="true">. For conditional rendering in Svelte one can achieve that by adding pure if blocks, wrapped in curly braces.

{#if Math.random() > 0.5}
  <p>I like Svelte.</p>
{:else}
  <p>I don't like Svelte.</p>
{/if}
Enter fullscreen mode Exit fullscreen mode

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.

Event Handler

Before the era of UI frameworks, developers used Vanilla JavaScript to add logic and behavior onto websites. Onclick 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:. 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:

<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>
Enter fullscreen mode Exit fullscreen mode

Let's talk about how to compose components next.

Composing Components

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

<script>
  import GridItem from '../components/GridItem.svelte';
</script>
Enter fullscreen mode Exit fullscreen mode

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

<GridItem></GridItem>
<!-- or <GridItem /> -->
Enter fullscreen mode Exit fullscreen mode

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.

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

<!-- 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>
Enter fullscreen mode Exit fullscreen mode

An optional default value can be added:

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

<h1>Hello {title}</h1>
Enter fullscreen mode Exit fullscreen mode

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

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 implemented a much more complex version of a Svelte-Grid.

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

<section>
  <slot></slot>
</section>
Enter fullscreen mode Exit fullscreen mode

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

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

<div>
  <slot name="title"></slot>
  <hr>
  <slot name="content"></slot>
  <slot></slot>
  <!-- or <slot /> -->
</div>
Enter fullscreen mode Exit fullscreen mode

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

<!-- 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>
Enter fullscreen mode Exit fullscreen mode

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.

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.

There is more to learn. Svelte offers lifecycle hooks, bindings, stores, transitions and much more to create more complex applications. Keep on learning πŸ‘¨β€πŸŽ“πŸ‘©β€πŸŽ“

Latest comments (7)

Collapse
 
bdougherty profile image
Brad Dougherty

One small correction: href={href} and href="{href}" both work. They are treated the same way by the Svelte compiler. Using quotes is helpful if you want just one part of the attribute to be dynamic, like href="https://example.com/{path}".

Collapse
 
danielrios549 profile image
Daniel Rios

Good to know that, the templates strings are good to use inside TS or JS code, but inside HTML I think this way better, almost identical to Python f-string

Collapse
 
marcradziwill profile image
Marc

Awesome overview thank you!

"...In my opinion, the principle to have a JavaScript (UI) framework without a framework is the most promising for the future of frontend development. ..."

I sign that. πŸ˜ƒ

Collapse
 
giorgosk profile image
Giorgos Kontopoulos πŸ‘€ • Edited

I have been attracted to it for the same reason "simplified frontend development"

Collapse
 
vannsl profile image
Vannsl

Thanks! Glad to hear that I'm not alone with that opinion :)

Collapse
 
marcradziwill profile image
Marc

Nope, you definitely not :)

Collapse
 
danielnetzer profile image
Daniel Netzer

Svelte is fantastic in so many ways. I expect it'll grow a lot in 2020