Bird
Raised Fist0
Svelteframework~5 mins

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

Choose your learning style10 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.

Practice

(1/5)
1. What is the main purpose of the click-outside action pattern in Svelte?
easy
A. To toggle a checkbox state on click
B. To open a tooltip when hovering over an element
C. To close a menu or popup when the user clicks outside of it
D. To fetch data from an API when clicking a button

Solution

  1. Step 1: Understand the click-outside pattern

    This pattern detects clicks outside a specific element to trigger an action, usually closing menus or popups.
  2. Step 2: Match purpose with options

    To close a menu or popup when the user clicks outside of it correctly describes closing menus/popups on outside clicks, while others describe unrelated behaviors.
  3. Final Answer:

    To close a menu or popup when the user clicks outside of it -> Option C
  4. Quick Check:

    click-outside closes menus on outside click = A [OK]
Hint: Click-outside closes popups when clicking outside them [OK]
Common Mistakes:
  • Confusing click-outside with tooltip behavior
  • Thinking it toggles element visibility on inside clicks
  • Assuming it triggers API calls
2. Which of the following is the correct way to use a clickOutside action in a Svelte component?
easy
A.
B.
C.
D.

Solution

  1. Step 1: Recall Svelte action syntax

    Svelte actions are used with the use: directive followed by the action name and optional parameters.
  2. Step 2: Identify correct syntax

    uses use:clickOutside, which is the correct way to apply an action. Other options misuse event or binding syntax.
  3. Final Answer:

    <div use:clickOutside={handleClickOutside}></div> -> Option D
  4. Quick Check:

    Actions use 'use:' directive = C [OK]
Hint: Use actions with 'use:' prefix in Svelte [OK]
Common Mistakes:
  • Using event syntax 'on:' instead of 'use:' for actions
  • Trying to bind actions with 'bind:'
  • Passing actions as plain attributes
3. Given this Svelte code snippet using a tooltip action:
  <button use:tooltip={{ text: 'Save changes' }}>Save</button>

What will happen when the user hovers over the button?
medium
A. A tooltip with the text 'Save changes' appears near the button
B. The button text changes to 'Save changes'
C. Nothing happens because the syntax is incorrect
D. The button is disabled

Solution

  1. Step 1: Understand tooltip action usage

    The tooltip action shows a small info box with the provided text when hovering or focusing the element.
  2. Step 2: Analyze the code behavior

    The button uses use:tooltip with text 'Save changes', so hovering triggers the tooltip display near the button.
  3. Final Answer:

    A tooltip with the text 'Save changes' appears near the button -> Option A
  4. Quick Check:

    Tooltip shows text on hover = A [OK]
Hint: Tooltip shows text on hover or focus [OK]
Common Mistakes:
  • Thinking tooltip changes button text
  • Assuming tooltip disables the button
  • Believing the syntax is invalid
4. Consider this Svelte snippet using a clickOutside action:
  <script>
    let open = true;
    function close() { open = false; }
  </script>
  <div use:clickOutside={close} >
    {#if open}
      <p>Menu content</p>
    {/if}
  </div>

Why might the menu not close when clicking outside?
medium
A. The clickOutside action is not imported or defined
B. The open variable is not reactive
C. The close function does not set open to true
D. The menu content is inside the div with the action

Solution

  1. Step 1: Check action usage requirements

    For use:clickOutside to work, the action must be imported or defined in the component.
  2. Step 2: Identify missing import or definition

    The snippet does not show any import or definition of clickOutside, so the action won't run, preventing menu close.
  3. Final Answer:

    The clickOutside action is not imported or defined -> Option A
  4. Quick Check:

    Missing action import = B [OK]
Hint: Always import or define actions before use [OK]
Common Mistakes:
  • Assuming variable reactivity is the issue
  • Confusing function logic with action setup
  • Ignoring the need to import or define actions
5. You want to create a tooltip that only appears when a button is focused or hovered, and disappears when clicking outside or losing focus. Which combination of Svelte patterns should you use?
hard
A. Use only CSS :hover and :focus styles without any actions
B. Use a tooltip action on the button and a clickOutside action on the tooltip container to hide it
C. Use a tooltip action on the button and toggle visibility with a manual click event
D. Use only a clickOutside action on the button to show and hide the tooltip

Solution

  1. Step 1: Understand tooltip and clickOutside roles

    The tooltip action shows info on hover/focus. The clickOutside action detects clicks outside to hide elements like tooltips.
  2. Step 2: Combine actions for desired behavior

    Using tooltip on the button shows the tooltip on hover/focus. Using clickOutside on the tooltip container hides it when clicking outside, ensuring it disappears properly.
  3. Final Answer:

    Use a tooltip action on the button and a clickOutside action on the tooltip container to hide it -> Option B
  4. Quick Check:

    Tooltip + clickOutside combo controls show/hide = D [OK]
Hint: Combine tooltip and clickOutside for show/hide control [OK]
Common Mistakes:
  • Using only clickOutside to show tooltip
  • Relying solely on CSS without accessibility
  • Manually toggling tooltip without outside click detection
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard