Custom Elements
How to use custom components or elements.
Using the custom snippet
Sometimes you wish to use your own components or just want to change the underlying element.
Using the custom snippet block on most Lithesome components, you’re able to just do that.
Here’s an example using the <Menu /> components.
<script>
import { Menu, MenuContent, MenuItem, MenuTrigger } from 'lithesome';
import { Button } from '$lib';
</script>
<Menu>
<MenuTrigger>
<Button>Click me</Button>
</MenuTrigger>
<MenuContent>
<MenuItem>Item 1</MenuItem>
<MenuItem>Item 2</MenuItem>
<MenuItem>Item 3</MenuItem>
</MenuContent>
</Menu>
Technically this does work. But if you were to view the resulting HTML, it’s wrapping a button inside another button. This is very bad for accessibility, event handling, ect…
To work around this, we use the custom snippet block and destructure the parameter and spread the attrs object.
The attrs object holds all the necessary logic and attributes.
<Menu>
<MenuTrigger>
{#snippet custom({ props })}
<Button {...props}>Click me</Button>
{/snippet}
</MenuTrigger>
<MenuContent>
<MenuItem>Item 1</MenuItem>
<MenuItem>Item 2</MenuItem>
<MenuItem>Item 3</MenuItem>
</MenuContent>
</Menu>
This will tell Lithesome not to render the default element but instead the user is going to provide the element to use.
Doing this also means you have access to either your own component API or raw HTML apis.
Svelte Transitions
By using the custom snippet, it also means we have access to the awesome svelte transition API.
Here an example:
<script>
import { Menu, MenuContent, MenuItem, MenuTrigger } from 'lithesome';
import { fly } from 'svelte/transition';
import { Button } from '$lib';
</script>
<Menu>
<MenuTrigger>
{#snippet custom({ props })}
<Button {...props}>Click me</Button>
{/snippet}
</MenuTrigger>
<MenuContent>
{#snippet custom({ props })}
<div transition:fly {...props}>
<MenuItem>Item 1</MenuItem>
<MenuItem>Item 2</MenuItem>
<MenuItem>Item 3</MenuItem>
</div>
{/snippet}
</MenuContent>
</Menu>
But if you were to follow this example, the <MenuContents /> will always be visible. Why is this?
Well the name implies a “custom implementation”. But do not fret, we also provide any necessary state to go along with the custom block if you do not wish to handle that by yourself.
Destructure the state object inside the custom params and acess the available state.
<Menu>
<MenuTrigger>
{#snippet custom({ props })}
<Button {...props}>Click me</Button>
{/snippet}
</MenuTrigger>
<MenuContent>
{#snippet custom({ props, state })}
{#if state.visible}
<div transition:fly {...props}>
<MenuItem>Item 1</MenuItem>
<MenuItem>Item 2</MenuItem>
<MenuItem>Item 3</MenuItem>
</div>
{/if}
{/snippet}
</MenuContent>
</Menu>
Lithesome is built using TypeScript, so you should get correct autocompletion on the state object show all the available state belonging to that snippet block.
If not, go to whatever component you’re using and check the API reference.