0Pricing
React Academy · Урок

Всплывающие подсказки и раскрывающиеся меню с порталами

Используйте порталы для отображения подсказок и раскрывающихся меню за пределами контейнеров overflow-hidden

«Всплывающие подсказки и раскрывающиеся меню с порталами» — бесплатный урок React Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения React Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс React Academy содержит 4 уроков всего.

Добро пожаловать

На этом уроке Вы создадите компоненты всплывающей подсказки и раскрывающегося списка, которые используют порталы React для отрисовки в document.body, обходя ограничения overflow-hidden у родителей и контекстов наложения z-index.

Проблема overflow

Всплывающая подсказка, расположенная относительно кнопки-триггера, будет обрезана, если у любого из её предков задано `overflow: hidden` или `overflow: scroll`. Перемещение подсказки в document.body через портал полностью решает эту проблему.

Стратегия позиционирования

Чтобы правильно расположить подсказку, отрисованную через портал, измерьте ограничивающий прямоугольник элемента-триггера с помощью `getBoundingClientRect()` и вычислите абсолютные координаты с учётом положения прокрутки.
const rect = triggerRef.current.getBoundingClientRect();
const top = rect.bottom + window.scrollY + 8;
const left = rect.left + window.scrollX;

Компонент всплывающей подсказки

Создайте Tooltip, который оборачивает свои дочерние элементы, прикрепляет ссылку к триггеру и при наведении создаёт через портал позиционированный блок подсказки.
function Tooltip({ content, children }) {
  const [visible, setVisible] = useState(false);
  const [pos, setPos] = useState({ top: 0, left: 0 });
  const ref = useRef();

  const show = () => {
    const r = ref.current.getBoundingClientRect();
    setPos({ top: r.bottom + window.scrollY + 4,
             left: r.left + window.scrollX });
    setVisible(true);
  };

  return (
    <span ref={ref} onMouseEnter={show} onMouseLeave={() => setVisible(false)}>
      {children}
      {visible && createPortal(
        <div style={{ position:'absolute', top: pos.top, left: pos.left }}
             className="tooltip">{content}</div>,
        document.body
      )}
    </span>
  );
}

Обновление позиции при прокрутке и изменении размера

Если пользователь прокручивает страницу, пока подсказка видима, её положение устаревает. Прослушивайте события `scroll` и `resize`, чтобы пересчитать положение или закрыть подсказку.
useEffect(() => {
  if (!visible) return;
  const update = () => setVisible(false);
  window.addEventListener('scroll', update, true);
  window.addEventListener('resize', update);
  return () => {
    window.removeEventListener('scroll', update, true);
    window.removeEventListener('resize', update);
  };
}, [visible]);

Архитектура раскрывающегося меню

Раскрывающееся меню использует тот же шаблон, что и всплывающая подсказка. Кнопка-триггер показывает или скрывает меню, меню отрисовывается через портал, а обработчик нажатия за пределами меню закрывает его.

Обработчик нажатия за пределами

Используйте обработчик `mousedown` на `document`, чтобы обнаруживать нажатия за пределами меню. Сравнивайте цель нажатия со ссылками на меню и триггер, чтобы решить, нужно ли закрыть меню.
useEffect(() => {
  if (!open) return;
  const handler = (e) => {
    if (!menuRef.current?.contains(e.target) &&
        !triggerRef.current?.contains(e.target)) {
      setOpen(false);
    }
  };
  document.addEventListener('mousedown', handler);
  return () => document.removeEventListener('mousedown', handler);
}, [open]);

Навигация с клавиатуры в раскрывающихся меню

Реализуйте ArrowDown/ArrowUp для перемещения между пунктами меню, Enter для выбора и Escape для закрытия. Храните индекс элемента в фокусе в состоянии и программно вызывайте `.focus()` у пунктов меню.

Использование библиотеки позиционирования

Для production-использования применяйте **@floating-ui/react** (ранее Popper.js). Она автоматически обрабатывает flip (изменение положения рядом с краями области просмотра), shift (сохранение подсказки видимой) и позиционирование стрелки.
import { useFloating, flip, shift } from '@floating-ui/react';

const { refs, floatingStyles } = useFloating({
  middleware: [flip(), shift()],
});

Доступность: ARIA для всплывающих подсказок

Для всплывающих подсказок добавьте `role='tooltip'` к элементу подсказки и `aria-describedby`, указывающий на id подсказки, к триггеру. Это позволяет программам чтения с экрана объявлять содержимое подсказки.
<button aria-describedby="tip1">Hover me</button>
{visible && createPortal(
  <div id="tip1" role="tooltip">Helpful text</div>,
  document.body
)}

Быстрая проверка

Как вычислить правильное положение всплывающей подсказки на экране, если она отрисована через портал?

Повторение

Порталы позволяют всплывающим подсказкам и выпадающим спискам выходить за пределы родительских элементов со скрытым переполнением. Измеряйте инициирующий элемент с помощью getBoundingClientRect, добавляйте смещения прокрутки для абсолютного позиционирования, закрывайте элементы при клике вне них и при прокрутке, а также добавляйте атрибуты ARIA для доступности.

Курс завершён

Поздравляем! Вы завершили курс **Порталы и модальные окна в React**. Теперь Вы умеете создавать доступные и правильно позиционированные модальные окна, всплывающие подсказки и выпадающие списки, не ограниченные рамками CSS-контекста наложения.

Часто задаваемые вопросы

Урок «Всплывающие подсказки и раскрывающиеся меню с порталами» бесплатный?

Да — полный текст урока «Всплывающие подсказки и раскрывающиеся меню с порталами» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс React Academy, подпишись на CoddyKit PRO. Курс React Academy содержит 4 уроков всего.

Чему я научусь в уроке «Всплывающие подсказки и раскрывающиеся меню с порталами»?

Используйте порталы для отображения подсказок и раскрывающихся меню за пределами контейнеров overflow-hidden Ты практикуешь React Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать React Academy?

Предыдущий опыт не требуется. React Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Всплывающие подсказки и раскрывающиеся меню с порталами»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке React Academy?

Да. Каждый урок React Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Что такое React Portals
  2. Создание модального компонента с порталами
  3. Управление фокусом и клавиатурные ловушки в модальных окнах
  4. Всплывающие подсказки и раскрывающиеся меню с порталами
← Назад к React Academy