Slots

In Svelte we can use slots to compose components meaning our components can contain other components and elements to be more reusable like regular HTML.

Example.htmlCopy

<button>
	<span>Child</span>
</button>

The <slot> element lets us do that with components. If you’re familiar with React this is similar to the children prop and Vue also has slots. We can provide a fallback if no content is provided.

Button.svelteCopy

<button>
  <slot>Placeholder</slot>
</button>

<style>
	button {
		color: teal;
	}
</style>

App.svelteCopy

<script>
	import Button from './Button.svelte'
</script>

<Button>
  <span>Child</span>
</Button>

<Button />

You can use named slots for more control over the placement of elements. If you want multiple elements going into the same slot use the <svelte:fragment> element as the wrapper.

Button.svelteCopy

<button>
	<slot name="icon"></slot>
	<slot name="text"></slot>
</button>

App.svelteCopy

<script>
	import Button from './Button.svelte'
</script>

<Button>
  <span slot="icon">➕</span>
	<span slot="text">Add</span>
</Button>

<Button>
  <span slot="icon">💩</span>
	<span slot="text">Delete</span>
</Button>

You might be asking when you’d use slots over regular components and the answer might be not often and that’s fine.

Here’s an example of slots and composition used in a real-world scenario in Svelte Cubed that’s a wrapper around Three.js so you write less code because it’s more declarative:

Example.svelteCopy

<script>
	import * as SC from 'svelte-cubed';
	import * as THREE from 'three';
</script>

<SC.Canvas>
	<SC.Mesh geometry={new THREE.BoxGeometry()} />
	<SC.PerspectiveCamera position={[1, 1, 3]} />
</SC.Canvas>

This is only a couple of lines of code compared to the equivalent Three.js code which has more than 20 lines of code and it’s harder to read.

There’s a lot more you can do with slot props but I encourage you to read the slots documentation because slots deserve their separate post.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *