DEV Community

Cover image for Svelte journey | Context API, Special Elements, Modularity, Debug
Denys Sych
Denys Sych

Posted on • Edited on

Svelte journey | Context API, Special Elements, Modularity, Debug

Welcome,

today on our plate are as many tasty topics as before in previous articles. We'll cover contexts that allow us to set up component communication in a way that differs from props and event dispatching, special Svelte elements that enable us to handle some cases that are not achievable with other tooling. Then, we'll move to modules in Svelte and wrap up with a couple of words about debugging.

Context

Similar to React’s Context concept. In a nutshell: can be used for component communication omitting props & events.

  • setContext and getContext must be called during component initialization;
  • Context can include anything, including stores, functions, objects, etc.
<!-- Parent.svelte -->
<script>
    import { setContext } from 'svelte';
    setContext('canvas', {
        addItem
    });

    function addItem(fn) {...}
</script>
// ...

<!-- Child.svelte -->
<script>
    import { getContext } from 'svelte';
    // ...
    getContext('canvas').addItem(draw);
    function draw(ctx) {...};
</script>
// ...
Enter fullscreen mode Exit fullscreen mode

Example with a store:

setContext('my-context', {
    count: writable(0)
});
const { count } = getContext('my-context')
$: console.log({ count: $count });
Enter fullscreen mode Exit fullscreen mode

Special elements — built-in Svelte utility elements

svelte:self

<svelte:self {...props} /> — render component inside itself recursively (e.g., useful for a folder tree view).

svelte:component

<svelte:component this={selected.component}/> — you can render a component that you store in some variable.

  • When a property changes, the component is destroyed and recreated;
  • Can be falsy value → in that case, no error is thrown & nothing is rendered.

Similar behavior in React:

import { FancyButton, UglyBanner } from 'my-pocket';

function Container() {
    const { isBelovedClient } = useClientService();
    const Component = isBelovedClient ? FancyButton : UglyBanner;

    return <Component />;
}
Enter fullscreen mode Exit fullscreen mode

In Svelte:

<script>
    import FancyButton from './FancyButton.svelte';
    import UglyBanner from './GreeUglyBannernThing.svelte';
    import isBelovedClient from './client-service.js';

    const targetComponent = isBelovedClient ? FancyButton : UglyBanner;
</script>
<svelte:component this={targetComponent}/>
Enter fullscreen mode Exit fullscreen mode

svelte:element

Pretty much the same as <svelte:component /> but for basic HTML elements, not Svelte components.

  • The only supported binding is bind:this (no bind:value. Why: Svelte binds at build time);
  • Runtime error in case some children inside a void element (like <br />).
<svelte:element this={'div'}>
    I'm a  div
</svelte:element>
Enter fullscreen mode Exit fullscreen mode

svelte:window

Interact with the window object. Supports bindings and handlers assignment.

<svelte:window on:keydown={handleKeydown} bind:scrollY={y} />
Enter fullscreen mode Exit fullscreen mode

Bind props (All except scrollX and scrollY are readonly):

  • innerWidth;
  • innerHeight;
  • outerWidth;
  • outerHeight;
  • scrollX;
  • scrollY;
  • online — an alias for window.navigator.onLine.

svelte:body

svelte:body is like svelte:window but for document.body. E.g., on:mouseenter and on:mouseleave are not available in window but in document.body.

svelte:document

Allows you to listen for events that fire on document. E.g., selectionchange.

svelte:head

Allows you to insert elements inside the <head> of the document.

<!-- App.svelte -->
<svelte:head>
    <link rel="stylesheet" href="/stylesheets/{selected}.css" />
</svelte:head>
Enter fullscreen mode Exit fullscreen mode
  • In SSR mode contents of <svelte:head> are returned separately from the rest of HTML.

svelte:options

To configure compiler options. There are a lot, a full list is better to check in the documentation.

  • Can be configured per component.

Example, telling the compiler that the component works with immutable data (by default Svelte works with mutable):

<svelte:options immutable />

<script>...</script>
...
Enter fullscreen mode Exit fullscreen mode

svelte:fragment

Similar to React.Fragment. When you need to group several elements/components without a container DOM element.

Can be used with slot

<svelte:fragment slot="game">
    <button />
    <input />
</svelte:fragment>
Enter fullscreen mode Exit fullscreen mode

Modularity

Run module code once

<script context="module"> — makes code run once, when the module first evaluates, not when the component initializes. You can have several <script /> tags per file, so it is possible to have default behavior as well:

<script context="module"> //
    let current;
</script>

<script>
    export let title;
    //...
</script>
Enter fullscreen mode Exit fullscreen mode

It gives you the ability to keep persistent state, have singletons, etc.

Imports & Exports

Anything exported from a context="module" script block becomes an export from the module itself.

No default export for the module, because the component itself is the default export.

// Player.svelte -----------------------------------------------------
<script context="module">
    let current;
    export const stopAll = () => current?.pause();
</script>
// ...
// App.svelte --------------------------------------------------------
<script>
    import AudioPlayer, { stopAll } from './AudioPlayer.svelte';
</script>
// ...
Enter fullscreen mode Exit fullscreen mode

You may remember also that if you do export from a regular <script /> it is also possible to access exported parts together with bind:this mechanism (bind:this section). The difference is that with context="module" you can do a particular import, and this code is not about a component instance but about a module, as it was mentioned before.

Debug

Old plain console.log(...) in the markup section or special {@debug ...} tag with a comma-separated list of values you want to inspect.

<script>
    let name = 'Ada';
</script>
<input bind:value={user.firstname} />

{@debug user}

<h1>Hello {user.firstname}!</h1>
Enter fullscreen mode Exit fullscreen mode

@debug with devtools opened also stops execution, shows a stack trace and other debug regular things.

I'm happy to share with you that this article is a finishing point of our Svelte’s overview! This article wraps up the part about Svelte as a UI library / component framework for building robust interfaces.

But it is not the finish line in our journey; it is just another turn over! In the next article, we’ll start to explore SvelteKit frameworkframework / metaframework, that provides surrounding tooling for building full-steam applications.

See you in the next articles,

take care, go Svelte!

Resources

  • Svelte Tutorial | Context API, Special Elements, Module context, Miscellaneous

Top comments (0)