Tippy.js — это мощная библиотека для создания всплывающих подсказок и тултипов в браузере. При использовании на клиенте она работает корректно «из коробки», но при интеграции в проекты с серверным рендерингом (SSR) и гидратацией возникают особенности, которые необходимо учитывать.
При SSR HTML контент формируется на сервере и отправляется готовым на клиент. В этом сценарии возникают следующие моменты:
Отсутствие DOM на сервере Tippy.js напрямую взаимодействует с DOM: создаёт элементы подсказок, рассчитывает позиции и размеры. На сервере DOM отсутствует, поэтому попытка инициализации тултипов до гидратации вызовет ошибки.
Нужна условная инициализация Инициализацию
Tippy.js следует выполнять только на клиенте, после того как DOM готов.
В React это обычно делают в useEffect:
import { useEffect } from 'react';
import tippy from 'tippy.js';
import 'tippy.js/dist/tippy.css';
function TooltipComponent() {
useEffect(() => {
tippy('#tooltip-target', {
content: 'Пример подсказки',
placement: 'top',
});
}, []);
return <button id="tooltip-target">Наведи на меня</button>;
}
Здесь useEffect гарантирует, что инициализация
произойдёт только на клиенте.
Избегание рендеринга тултипов на сервере Любые динамические элементы Tippy.js не должны рендериться в HTML на сервере. Если требуется SSR-дружественный контент, можно отображать только целевой элемент, а тултип создавать уже на клиенте.
Гидратация — это процесс привязки клиентских скриптов к уже существующему серверному HTML. Для Tippy.js важны следующие нюансы:
Совмещение с React/Vue/Svelte
useEffect).onMounted:import { onMounted } from 'vue';
import tippy from 'tippy.js';
export default {
setup() {
onMounted(() => {
tippy('#tooltip-vue', {
content: 'Тултип Vue',
});
});
},
};Гидратация сложного контента Tippy.js
поддерживает HTML-контент и даже React-компоненты через
render. Однако при SSR важно не рендерить эти элементы на
сервере полностью. Пример использования React-подсказки с
гидратацией:
import ReactDOM from 'react-dom';
import tippy, { createSingleton } from 'tippy.js';
function MyTooltip() {
return <div>Динамический контент</div>;
}
useEffect(() => {
const instance = tippy('#tooltip-react', {
render(reference) {
const div = document.createElement('div');
ReactDOM.render(<MyTooltip />, div);
return {
popper: div,
reference,
};
},
});
return () => {
instance.destroy();
};
}, []);
Здесь ReactDOM.render выполняется только на клиенте, что
обеспечивает корректную гидратацию.
Избегание ошибок двойного рендеринга В SSR
приложениях важно, чтобы тултип не создавался дважды: один раз сервером,
второй раз клиентом. Использование условного рендеринга на клиенте
(if (typeof window !== 'undefined')) предотвращает эту
проблему.
tippy.hideOnClick и
trigger: позволяет контролировать момент
отображения и минимизировать вмешательство в серверный HTML.| Параметр | Рекомендации для SSR и гидратации |
|---|---|
appendTo |
Использовать document.body на клиенте, не пытаться
рендерить на сервере |
interactive |
Включать только для клиентских тултипов, чтобы избежать ошибок позиционирования |
animation |
Можно отключить или использовать только после гидратации для плавности |
render |
Динамический контент следует создавать только на клиенте |
Tippy.js в средах SSR требует строгого разделения серверного и клиентского рендеринга. Основная идея — не инициировать тултипы на сервере, создавать их динамически после гидратации и использовать условный код для работы с DOM. Это обеспечивает корректное позиционирование, интерактивность и минимизацию ошибок при переходе от SSR к клиентскому рендерингу.