Svelte journey | Context API, Special Elements, Modularity, Debug
Tags: javascript, tutorial, svelte, frontend
Published: 2023-12-30 15:17:41

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.

```jsx
<!-- 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>
// ...
```

Example with a store:

```jsx
setContext('my-context', {
	count: writable(0)
});
const { count } = getContext('my-context')
$: console.log({ count: $count });
```

## 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:

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

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

	return <Component />;
}
```

In Svelte:

```jsx
<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}/>
```

### 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 />`).

```jsx
<svelte:element this={'div'}>
	I'm a  div
</svelte:element>
```

### svelte:window

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

```jsx
<svelte:window on:keydown={handleKeydown} bind:scrollY={y} />
```

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.

```jsx
<!-- App.svelte -->
<svelte:head>
	<link rel="stylesheet" href="/stylesheets/{selected}.css" />
</svelte:head>
```

- In SSR mode contents of `<svelte:head>` are returned separately from the rest of HTML.

### svelte:options

To configure [compiler options](https://svelte.dev/docs/svelte-compiler#compile). 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):

```jsx
<svelte:options immutable />

<script>...</script>
...
```

### svelte:fragment

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

Can be used with `slot`

```jsx
<svelte:fragment slot="game">
	<button />
	<input />
</svelte:fragment>
```

## 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:

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

<script>
	export let title;
	//...
</script>
```

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

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

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](https://dev.to/chillyhill/svelte-journey-actions-advanced-bindings-classes-styles-slots-2en3)). 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.

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

{@debug user}

<h1>Hello {user.firstname}!</h1>
```

`@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 framework** — *framework / metaframework*, that provides surrounding tooling for building full-steam applications.

See you in the next articles,

take care, go Svelte!

## Resources

- [Svelte Tutorial](https://learn.svelte.dev/tutorial) | Context API, Special Elements, Module context, Miscellaneous