Настройка содержимого тултипа

Библиотека Tippy.js предоставляет гибкие способы задания содержимого всплывающих подсказок. Основные варианты:

  • Строка (текст)
  • HTML-разметка
  • DOM-элемент
  • Функция (динамическое содержимое)

Базовый пример с текстом:

tippy('#button', {
  content: 'Простая подсказка'
});

Использование HTML

Для отображения форматированного содержимого используется HTML. По умолчанию HTML отключён из соображений безопасности, поэтому необходимо явно разрешить его через опцию allowHTML.

tippy('#button', {
  content: '<strong>Жирный текст</strong> и <em>курсив</em>',
  allowHTML: true
});

Особенности:

  • Поддерживаются любые валидные HTML-теги
  • Можно использовать стили и классы
  • Требуется осторожность при работе с пользовательским вводом (XSS)

Передача DOM-элемента

Вместо строки можно передать уже существующий элемент:

const template = document.querySelector('#tooltip-template');

tippy('#button', {
  content: template
});

Поведение:

  • Элемент будет перемещён в тултип, а не скопирован
  • После инициализации он исчезнет из исходного места в DOM

Чтобы избежать этого, используется клонирование:

tippy('#button', {
  content: template.cloneNode(true)
});

Динамическое содержимое через функцию

Функция позволяет генерировать содержимое на лету:

tippy('#button', {
  content(reference) {
    return `ID элемента: ${reference.id}`;
  }
});

Аргумент reference — это элемент, к которому привязан тултип.

Пример с изменением данных

tippy('.item', {
  content(reference) {
    return reference.getAttribute('data-info');
  }
});

Работа с атрибутами data-*

Tippy.js по умолчанию умеет брать содержимое из атрибута data-tippy-content:

<button data-tippy-content="Подсказка">Наведи</button>
tippy('button');

Переопределение атрибута

Можно использовать другой атрибут:

tippy('button', {
  content(reference) {
    return reference.getAttribute('data-custom');
  }
});

Асинхронное содержимое

Для загрузки данных с сервера используется асинхронный подход:

tippy('#button', {
  content: 'Загрузка...',
  onShow(instance) {
    fetch('/api/data')
      .then(response => response.text())
      .then(data => {
        instance.setContent(data);
      });
  }
});

Ключевые моменты:

  • Изначально задаётся временное содержимое
  • После получения данных вызывается setContent

Обновление содержимого

Метод setContent позволяет менять текст тултипа динамически:

const instance = tippy('#button', {
  content: 'Старое значение'
});

instance.setContent('Новое значение');

Если используется делегирование:

tippy('#container', {
  target: '.child',
  content: 'Общее содержимое'
});

Обновление происходит через экземпляр:

instance.setContent('Обновлено');

Использование шаблонов

Часто применяется скрытый HTML-шаблон:

<div id="tpl" style="display: none;">
  <div class="tooltip-content">
    <h4>Заголовок</h4>
    <p>Описание</p>
  </div>
</div>
tippy('#button', {
  content: document.querySelector('#tpl').innerHTML,
  allowHTML: true
});

Встраивание интерактивных элементов

Внутри тултипа могут находиться кнопки, формы и другие элементы:

tippy('#button', {
  content: `
    <button oncl ick="alert('Нажато')">Кнопка</button>
  `,
  allowHTML: true,
  interactive: true
});

Опция interactive: true необходима, чтобы тултип не закрывался при взаимодействии.

Контроль безопасности

При использовании HTML важно учитывать:

  • Не вставлять необработанный пользовательский ввод
  • Использовать санитайзеры (например DOMPurify)
import DOMPurify from 'dompurify';

tippy('#button', {
  content: DOMPurify.sanitize(userInput),
  allowHTML: true
});

Ленивая инициализация содержимого

Для оптимизации можно откладывать генерацию:

tippy('#button', {
  content: '...',
  onShow(instance) {
    if (!instance._loaded) {
      instance.setContent('Данные загружены');
      instance._loaded = true;
    }
  }
});

Работа с несколькими элементами

tippy('.buttons', {
  content(reference) {
    return `Кнопка: ${reference.textContent}`;
  }
});

Каждый элемент получает собственное содержимое.

Комбинирование подходов

Можно сочетать разные техники:

tippy('.item', {
  allowHTML: true,
  content(reference) {
    const title = reference.getAttribute('data-title');
    const desc = reference.getAttribute('data-desc');

    return `
      <strong>${title}</strong>
      <div>${desc}</div>
    `;
  }
});

Кастомизация структуры тултипа

Через render API можно полностью контролировать DOM:

tippy('#button', {
  render(instance) {
    const popper = document.createElement('div');
    popper.className = 'custom-tooltip';

    const content = document.createElement('div');
    content.className = 'content';
    content.textContent = instance.props.content;

    popper.appendChild(content);

    return {
      popper,
      onUpdate(prevProps, nextProps) {
        content.textContent = nextProps.content;
      }
    };
  }
});

Обработка событий изменения содержимого

Событие onUpdate позволяет реагировать на изменения:

tippy('#button', {
  content: 'Начало',
  onUpdate(instance) {
    console.log('Содержимое обновлено:', instance.props.content);
  }
});

Использование Markdown

При необходимости можно преобразовывать Markdown:

import marked from 'marked';

tippy('#button', {
  allowHTML: true,
  content: marked('# Заголовок\n\nТекст')
});

Особенности производительности

  • Частое обновление содержимого может вызывать перерисовку
  • Лучше кэшировать данные
  • Использовать onShow, а не пересоздавать тултип

Ограничения

  • Один DOM-элемент не может одновременно находиться в нескольких тултипах
  • Inline-события (onclick) работают, но не рекомендуются
  • При сложной логике лучше использовать полноценные компоненты (например, через React/Vue интеграции)

Практический пример

tippy('.user', {
  allowHTML: true,
  interactive: true,
  content(reference) {
    const name = reference.dataset.name;
    const email = reference.dataset.email;

    return `
      <div class="user-card">
        <strong>${name}</strong>
        <div>${email}</div>
        <button class="send">Написать</button>
      </div>
    `;
  },
  onShow(instance) {
    const btn = instance.popper.querySelector('.send');
    btn.addEventListener('click', () => {
      alert('Сообщение отправлено');
    });
  }
});

Такой подход демонстрирует создание полноценных интерактивных карточек внутри тултипов с динамическими данными.