0
0
Svelteframework~5 mins

Common action patterns (click-outside, tooltip) in Svelte

Choose your learning style9 modes available
Introduction

These patterns help make your app interactive and user-friendly. Click-outside closes menus when clicking outside them. Tooltip shows helpful info when hovering or focusing on elements.

You want to close a dropdown menu when the user clicks anywhere outside it.
You want to show extra info when the user hovers over a button or icon.
You want to improve accessibility by showing tooltips on keyboard focus.
You want to hide popups or modals when clicking outside them.
You want to add small hints or explanations without cluttering the UI.
Syntax
Svelte
function clickOutside(node) {
  const handleClick = event => {
    if (!node.contains(event.target)) {
      node.dispatchEvent(new CustomEvent('outclick'));
    }
  };
  document.addEventListener('click', handleClick, true);
  return {
    destroy() {
      document.removeEventListener('click', handleClick, true);
    }
  };
}

function tooltip(node, text) {
  let tooltipDiv;
  function mouseOver() {
    if (tooltipDiv) {
      tooltipDiv.remove();
    }
    tooltipDiv = document.createElement('div');
    tooltipDiv.textContent = text;
    tooltipDiv.style.position = 'absolute';
    tooltipDiv.style.background = 'black';
    tooltipDiv.style.color = 'white';
    tooltipDiv.style.padding = '0.25rem 0.5rem';
    tooltipDiv.style.borderRadius = '0.25rem';
    tooltipDiv.style.fontSize = '0.75rem';
    tooltipDiv.style.zIndex = '1000';
    document.body.appendChild(tooltipDiv);
    const rect = node.getBoundingClientRect();
    tooltipDiv.style.top = `${rect.bottom + 5}px`;
    tooltipDiv.style.left = `${rect.left}px`;
  }
  function mouseOut() {
    if (tooltipDiv) {
      tooltipDiv.remove();
      tooltipDiv = null;
    }
  }
  node.addEventListener('mouseover', mouseOver);
  node.addEventListener('mouseout', mouseOut);
  node.addEventListener('focus', mouseOver);
  node.addEventListener('blur', mouseOut);
  return {
    destroy() {
      if (tooltipDiv) {
        tooltipDiv.remove();
        tooltipDiv = null;
      }
      node.removeEventListener('mouseover', mouseOver);
      node.removeEventListener('mouseout', mouseOut);
      node.removeEventListener('focus', mouseOver);
      node.removeEventListener('blur', mouseOut);
    }
  };
}

The clickOutside action listens for clicks outside the element and triggers a custom event.

The tooltip action creates a small popup near the element on hover or focus, improving accessibility.

Examples
This example shows a dropdown menu that closes when you click outside it using the clickOutside action.
Svelte
<script>
  import { clickOutside } from './actions.js';
  let open = false;
  function toggle() {
    open = !open;
  }
  function close() {
    open = false;
  }
</script>

<button on:click={toggle}>Toggle Menu</button>
{#if open}
  <div use:clickOutside on:outclick={close} tabindex="0">
    <p>This menu closes when clicking outside.</p>
  </div>
{/if}
This example adds a tooltip to a button that appears on hover or keyboard focus.
Svelte
<script>
  import { tooltip } from './actions.js';
</script>

<button use:tooltip={'Click me for info'} aria-describedby="tip1">Hover or focus me</button>
Sample Program

This Svelte component shows a button with a tooltip. When clicked, it opens a menu. Clicking outside the menu closes it. The menu and tooltip improve user experience and accessibility.

Svelte
<script>
  // Actions defined inside the component for simplicity
  function clickOutside(node) {
    const handleClick = event => {
      if (!node.contains(event.target)) {
        node.dispatchEvent(new CustomEvent('outclick'));
      }
    };
    document.addEventListener('click', handleClick, true);
    return {
      destroy() {
        document.removeEventListener('click', handleClick, true);
      }
    };
  }

  function tooltip(node, text) {
    let tooltipDiv;
    function mouseOver() {
      if (tooltipDiv) {
        tooltipDiv.remove();
      }
      tooltipDiv = document.createElement('div');
      tooltipDiv.textContent = text;
      tooltipDiv.style.position = 'absolute';
      tooltipDiv.style.background = 'black';
      tooltipDiv.style.color = 'white';
      tooltipDiv.style.padding = '0.25rem 0.5rem';
      tooltipDiv.style.borderRadius = '0.25rem';
      tooltipDiv.style.fontSize = '0.75rem';
      tooltipDiv.style.zIndex = '1000';
      document.body.appendChild(tooltipDiv);
      const rect = node.getBoundingClientRect();
      tooltipDiv.style.top = `${rect.bottom + 5}px`;
      tooltipDiv.style.left = `${rect.left}px`;
    }
    function mouseOut() {
      if (tooltipDiv) {
        tooltipDiv.remove();
        tooltipDiv = null;
      }
    }
    node.addEventListener('mouseover', mouseOver);
    node.addEventListener('mouseout', mouseOut);
    node.addEventListener('focus', mouseOver);
    node.addEventListener('blur', mouseOut);
    return {
      destroy() {
        if (tooltipDiv) {
          tooltipDiv.remove();
          tooltipDiv = null;
        }
        node.removeEventListener('mouseover', mouseOver);
        node.removeEventListener('mouseout', mouseOut);
        node.removeEventListener('focus', mouseOver);
        node.removeEventListener('blur', mouseOut);
      }
    };
  }

  let menuOpen = false;
  function toggleMenu() {
    menuOpen = !menuOpen;
  }
  function closeMenu() {
    menuOpen = false;
  }
</script>

<button on:click={toggleMenu} use:tooltip={'Toggle menu'} aria-haspopup="true" aria-expanded={menuOpen}>Menu</button>

{#if menuOpen}
  <div use:clickOutside on:outclick={closeMenu} tabindex="0" style="border: 1px solid #ccc; padding: 1rem; margin-top: 0.5rem; width: 200px; background: #f9f9f9;">
    <p>This menu closes when clicking outside.</p>
    <button on:click={closeMenu}>Close</button>
  </div>
{/if}
OutputSuccess
Important Notes

Use tabindex="0" on elements with clickOutside to make them focusable for keyboard users.

Tooltips should appear on keyboard focus as well as mouse hover for accessibility.

Remember to clean up event listeners in the destroy method to avoid memory leaks.

Summary

Click-outside helps close menus or popups when clicking outside them.

Tooltip shows helpful info on hover or focus, improving user experience.

Both patterns improve accessibility and interactivity in your Svelte apps.