CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-tippy-js

The complete tooltip, popover, dropdown, and menu solution for the web

Pending
Overview
Eval results
Files

event-delegation.mddocs/

Event Delegation

Advanced event delegation system for handling tooltips on dynamically created elements and managing large sets of tooltip triggers efficiently.

Capabilities

Delegate Function

Creates delegate instances that automatically handle tooltip creation for child elements matching a CSS selector, perfect for dynamic content and large element sets.

/**
 * Creates a delegate instance that controls tooltip creation for child elements
 * @param targets - Parent elements to monitor for delegation
 * @param props - Tooltip properties including required target selector
 * @returns Delegate instance(s) with enhanced destroy method
 */
function delegate(
  targets: Element | Element[] | NodeList | string,
  props: Partial<Props> & { target: string }
): DelegateInstance | DelegateInstance[];

interface DelegateInstance<TProps = Props> extends Instance<TProps> {
  /** Destroy delegate and optionally destroy target instances */
  destroy(shouldDestroyTargetInstances?: boolean): void;
}

Usage Examples:

import { delegate } from "tippy.js";

// Basic delegation for dynamically added elements
const delegateInstance = delegate('#container', {
  target: '.tooltip-target', // CSS selector for child elements
  content: 'Delegated tooltip',
  placement: 'top'
});

// Add elements dynamically - tooltips are created automatically
const container = document.querySelector('#container');
container.innerHTML += '<button class="tooltip-target">New Button</button>';

// Delegation with dynamic content
delegate('.list-container', {
  target: '.list-item',
  content(reference) {
    return reference.getAttribute('data-tooltip') || 'Default content';
  },
  allowHTML: true
});

// Multiple containers with shared configuration
delegate(['.sidebar', '.main-content'], {
  target: '[data-tippy]',
  content(reference) {
    return reference.dataset.tippy;
  },
  placement: 'auto'
});

Dynamic Element Handling

Automatic tooltip creation and cleanup for elements that are added or removed from the DOM after delegation is set up.

// Delegation automatically handles:
// - Elements added after delegation setup
// - Different trigger types per element (via data attributes)
// - Custom content per element
// - Cleanup when elements are removed

Usage Examples:

import { delegate } from "tippy.js";

// Set up delegation for a dynamic list
const listDelegate = delegate('#dynamic-list', {
  target: '.list-item',
  content(reference) {
    return `Item: ${reference.textContent}`;
  },
  trigger: 'mouseenter focus'
});

// Elements added later automatically get tooltips
function addListItem(text) {
  const item = document.createElement('div');
  item.className = 'list-item';
  item.textContent = text;
  document.querySelector('#dynamic-list').appendChild(item);
  // Tooltip is automatically available on this new element
}

// Different triggers per element using data attributes
delegate('#mixed-triggers', {
  target: '.interactive-element',
  content: 'Flexible tooltip',
  // Individual elements can override trigger via data-tippy-trigger
});

// HTML in list:
// <div class="interactive-element" data-tippy-trigger="click">Click me</div>
// <div class="interactive-element" data-tippy-trigger="mouseenter">Hover me</div>

Delegate Instance Management

Enhanced instance management with child tooltip control and bulk operations.

interface DelegateInstance<TProps = Props> extends Instance<TProps> {
  /** Standard instance methods inherited */
  show(): void;
  hide(): void;
  enable(): void;
  disable(): void;
  destroy(shouldDestroyChildInstances?: boolean): void;
}

Usage Examples:

import { delegate } from "tippy.js";

const delegateInstance = delegate('#parent', {
  target: '.child',
  content: 'Child tooltip'
});

// Control all child tooltips via delegate
delegateInstance.enable(); // Enable all child tooltips
delegateInstance.disable(); // Disable all child tooltips

// Destroy with options
delegateInstance.destroy(true); // Destroy delegate and all child instances
delegateInstance.destroy(false); // Destroy delegate but keep child instances

// The delegate instance itself can be shown/hidden
delegateInstance.show(); // This won't work as expected - delegates don't have their own tooltip

Performance Optimization

Delegation provides significant performance benefits for large numbers of elements by using event bubbling instead of individual event listeners.

// Performance comparison:
// Individual tooltips: N event listeners for N elements
// Delegated tooltips: 4 event listeners total (touch, mouse, focus, click)

Usage Examples:

import { delegate } from "tippy.js";

// Efficient for large tables
delegate('#data-table', {
  target: 'td[data-tooltip]',
  content(reference) {
    return reference.dataset.tooltip;
  },
  delay: [500, 100] // Reduce accidental triggers
});

// Efficient for dynamic grids
delegate('.image-grid', {
  target: '.image-item',
  content(reference) {
    const img = reference.querySelector('img');
    return `
      <div>
        <strong>${img.alt}</strong><br>
        ${img.dataset.description || 'No description'}
      </div>
    `;
  },
  allowHTML: true,
  placement: 'bottom'
});

// Memory efficient infinite scroll
const infiniteDelegate = delegate('#infinite-scroll', {
  target: '.scroll-item',
  content: 'Tooltip for scroll item'
});

// No need to manage tooltips when items are removed/added
// Delegation handles it automatically

Advanced Delegation Patterns

Complex delegation scenarios with conditional logic and nested delegation.

Usage Examples:

import { delegate } from "tippy.js";

// Conditional delegation based on element state
delegate('#conditional-container', {
  target: '.conditional-target',
  content(reference) {
    if (reference.classList.contains('disabled')) {
      return 'This feature is disabled';
    }
    return reference.getAttribute('data-help') || 'No help available';
  },
  onTrigger(instance, event) {
    // Additional logic on trigger
    if (event.target.classList.contains('no-tooltip')) {
      return; // Skip tooltip creation
    }
  }
});

// Nested delegation for complex layouts
delegate('#outer-container', {
  target: '.section',
  content: 'Section tooltip'
});

delegate('#outer-container', {
  target: '.section .item',
  content: 'Item tooltip',
  placement: 'right'
});

// Context-aware delegation
delegate('.context-sensitive', {
  target: '[data-context-help]',
  content(reference) {
    const context = reference.closest('[data-context]')?.dataset.context;
    const helpKey = reference.dataset.contextHelp;
    return getContextualHelp(context, helpKey);
  },
  interactive: true,
  allowHTML: true
});

Install with Tessl CLI

npx tessl i tessl/npm-tippy-js

docs

core-tooltip.md

event-delegation.md

global-utilities.md

index.md

plugins.md

singleton-tooltips.md

tile.json