0
0
SvelteHow-ToBeginner · 4 min read

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 capture phase (true as 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 true to addEventListener for 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.