How to Create Click Outside Action in Svelte Easily
In Svelte, create a custom
clickOutside action that listens for clicks on the document and checks if the click target is outside the element. Attach this action to any element with use:clickOutside to run a callback when clicking outside that element.Syntax
The clickOutside action is a function that takes an element and a callback function. It adds a click event listener to the document to detect clicks anywhere. If the click is outside the element, it calls the callback.
Attach it in your component with use:clickOutside={callback}.
javascript
function clickOutside(node, callback) { const handleClick = event => { if (!node.contains(event.target)) { callback(); } }; document.addEventListener('click', handleClick, true); return { destroy() { document.removeEventListener('click', handleClick, true); } }; }
Example
This example shows a dropdown menu that closes when you click outside it. The clickOutside action calls a function to hide the menu when a click happens outside the dropdown.
svelte
<script> let open = false; function clickOutside(node, callback) { const handleClick = event => { if (!node.contains(event.target)) { callback(); } }; document.addEventListener('click', handleClick, true); return { destroy() { document.removeEventListener('click', handleClick, true); } }; } function closeMenu() { open = false; } </script> <button on:click={() => open = !open} aria-haspopup="true" aria-expanded={open}> Toggle Menu </button> {#if open} <div use:clickOutside={closeMenu} tabindex="-1" role="menu" aria-label="Dropdown menu" style="border: 1px solid #ccc; padding: 1rem; margin-top: 0.5rem; width: 200px; background: white;"> <p>Menu Item 1</p> <p>Menu Item 2</p> <p>Menu Item 3</p> </div> {/if}
Output
A button labeled 'Toggle Menu'. When clicked, a white box with three menu items appears below. Clicking outside the box closes it.
Common Pitfalls
- Not removing the event listener on destroy causes memory leaks.
- Using
event.stopPropagation()inside the element can block the outside click detection. - Not using
capturephase (trueas third argument) can cause missed clicks if other handlers stop propagation.
javascript
/* Wrong: No cleanup and no capture phase */ function clickOutside(node, callback) { const handleClick = event => { if (!node.contains(event.target)) { callback(); } }; document.addEventListener('click', handleClick); // no capture // missing destroy cleanup } /* Correct: Cleanup and capture phase */ function clickOutside(node, callback) { const handleClick = event => { if (!node.contains(event.target)) { callback(); } }; document.addEventListener('click', handleClick, true); // capture phase return { destroy() { document.removeEventListener('click', handleClick, true); } }; }
Quick Reference
- Attach action:
use:clickOutside={callback} - Callback: Runs when click is outside element
- Cleanup: Remove event listener in
destroy() - Use capture phase: Pass
truetoaddEventListenerfor reliable detection
Key Takeaways
Create a custom action that listens for document clicks and checks if the click is outside the element.
Always remove event listeners in the action's destroy method to avoid memory leaks.
Use the capture phase in event listeners to catch clicks before other handlers stop propagation.
Attach the action with
use:clickOutside and provide a callback to handle outside clicks.Avoid stopping event propagation inside the element to ensure outside clicks are detected.