Some components in Tailwind UI have dynamic functionality that requires Javascript to implement. The original dynamic code for Tailwind UI was written using Alpine.js, and I put together this list of how to implement the techniques in Svelte back in March 2020.
Tailwind UI has since changed to use informative comments instead of Alpine code samples, but the Svelte techniques below still apply.
Conditional Showing of Elements
Alpine:
<div x-data="{open: true}">
<div x-show="open">...</div>
</div>
Svelte:
<script>
let open = true;
</script>
<div>
{#if open}
<div>...</div>
{/if}
</div>
Conditional Classes
Alpine:
<div :class="{'block': open, 'hidden': !open}">...</div>
Svelte:
<div class:block={open} class:hidden={!open}>...</div>
Event Handlers
Button Click
Alpine:
<button @click="open = !open">...</button>
Svelte:
<button on:click={() => open = !open}>...</button>
Click Outside
Alpine:
<div @click.away="open = false">
...
<div x-show={open}>...</div>
</div>
Svelte (REPL):
<script>
function clickOutside(node, { enabled: initialEnabled, cb }) {
const handleOutsideClick = ({ target }) => {
if (!node.contains(target)) {
cb();
}
};
function update({enabled}) {
if (enabled) {
window.addEventListener('click', handleOutsideClick);
} else {
window.removeEventListener('click', handleOutsideClick);
}
}
update(initialEnabled);
return {
update,
destroy() {
window.removeEventListener( 'click', handleOutsideClick );
}
};
}
let open = true;
</script>
<div use:clickOutside={{ enabled: open, cb: () => open = false }}>
<button>...</button>
{#if open}
<div>
...
</div>
{/if}
</div>
Key Press
Alpine:
<div @keydown.window.escape="open = false">
...
</div>
Svelte:
<script>
function handleEscape({key}) {
if (key === 'Escape') {
open = false;
}
}
</script>
<svelte:window on:keyup={handleEscape} />
{#if open}
<div>...</div>
{/if}
This could also be done with a use:
action similar to the Click Outside example.
Transitions
Alpine
<div
x-transition:enter="transition ease-out duration-100"
x-transition:enter-start="transform opacity-0 scale-95"
x-transition:enter-end="transform opacity-100 scale-100"
x-transition:leave="transition ease-in duration-75"
x-transition:leave-start="transform opacity-100 scale-100"
x-transition:leave-end="transform opacity-0 scale-95">
...
</div>
Svelte
<script>
import { scale } from 'svelte/transition';
import { cubicIn, cubicOut } from 'svelte/easing';
</script>
<div in:scale={{ duration: 100, start: 0.95, easing: cubicOut }}
out:scale={{ duration: 75, start: 0.95, easing: cubicIn }}>
Start is the scale value divided by 100.
</div>
Top comments (2)
Excellent! This is what I was looking for. Thank you for the post.
Do you know how to change this to Svelte?
Glad you liked it! You might also want to check out github.com/rgossiaux/svelte-headle... which is a Svelte port of Tailwind's "Headless UI" component library. I haven't used it myself yet but it looks promising.
And for your question, Svelte's equivalent is this: