Svelte 38: Module D Capstone: Effects, Timing & Polish
easy⏱ 5 mincoursesvelte
Each toast owns its own $effect timer
Extracting ToastItem into its own component gives each toast an independent $effect: on mount it calls setTimeout(dismiss, duration), and the function it returns from $effect runs as cleanup — either when the component is destroyed early (manual close) or, in principle, if its dependencies changed. That returned cleanup is what makes clearTimeout actually fire instead of leaking a timer for a toast that no longer exists.
<script>
let { duration, onDismiss } = $props();
$effect(() => {
const timer = setTimeout(onDismiss, duration);
return () => clearTimeout(timer);
});
</script>
clickOutside is just another action with destroy()
The composer panel's use:clickOutside={() => composerOpen = false} attaches a capturing document click listener that checks node.contains(event.target), and its destroy() removes that listener the moment the panel itself is removed — so no global listener survives after the panel closes, whether it closed via an outside click or any other path.
Assemble the toast studio
Wire the quick-fire buttons, the composer (transition + clickOutside), and the ToastItem stack (transition + self-cleaning $effect) into one working widget.
Module D recap
You've now covered the full real-world forms & polish toolbox: every native binding (checkbox, radio group, select, textarea) plus $bindable() props for your own components, built-in transitions split across in:/out:, hand-written transition functions paired with svelte/easing, animate:flip for reordering lists, physics-based spring motion, and full-lifecycle custom actions with update()/destroy() — everything this toast system leans on at once.