5 лучших библиотек всплывающих окон для React

5 лучших библиотек всплывающих окон для React

Содержание
  1. Почему именно библиотеки поповеров?
  2. Проблема размещения
  3. Проблемы с обрезанием
  4. 1. Popper.js: Механизм позиционирования всплывающих окон и всплывающих подсказок
    1. Использование react-popper без createPortal
  5. 2. react-tiny-popover: Легкая, но яркая библиотека
    1. Установка и использование react-tiny-popover
  6. 3. react-laag
    1. Настройка и использование react-laag
    2. Настройка и использование reactjs-popup
  7. 5. React Joyride: Экскурсии с помощью всплывающих окон
    1. Настройка и использование React Joyride
  8. Сравнительная таблица библиотек всплывающих окон React
  9. Заключение

Всплывающие окна - это важные и часто используемые элементы пользовательского интерфейса, которые раскрывают дополнительную информацию, когда пользователь взаимодействует с определенным элементом. Примерами профессионального использования всплывающих окон являются выпадающие навигационные меню, переключатели дат, а также экскурсии в процессе регистрации.

В экосистеме React существует множество библиотек для удовлетворения этих потребностей, предлагающих различные уровни кастомизации, стратегии расположения и отзывчивости. В этом подробном руководстве мы рассмотрим пять лучших библиотек всплывающих окон и позиционирования для React:

  • Popper.js
  • react-tiny-popover
  • react-laag
  • reactjs-popup
  • React Joyride

Для каждой из этих библиотек мы рассмотрим их настройку, возможности позиционирования, отзывчивость и многое другое, используя один и тот же базовый демо-проект, чтобы увидеть каждую библиотеку в действии. Вы можете посмотреть код и демонстрации на CodeSandbox или перейти к концу, чтобы увидеть сравнительную таблицу для всех пяти библиотек.

Прежде чем мы перейдем к рассмотрению библиотек, давайте сначала обсудим, почему вам стоит использовать библиотеки для поповеров, а не создавать поповеры с нуля.

Почему именно библиотеки поповеров?

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

Давайте рассмотрим простой многократно используемый компонент всплывающего окна, созданный с нуля.

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

Для достижения этой цели в React необходимо создать состояние компонента для переключения содержимого всплывающего окна и применить position: absolute к всплывающему окну, чтобы выровнять его по элементу ссылки. Следующий код должен вывести настраиваемое всплывающее окно:

const TableItem = ({ ... }) => {
  const [popoverOpen, setPopoverOpen] = useState(false);

  return (
    <Popover isOpen={popoverOpen} content={<div className="popover-content">{/* content */}</div>}>
      <div className="btn-container" onClick={() => setPopoverOpen(!popoverOpen)}>
        <Button label="Admin" />
        <RxCaretSort />
      </div>
    </Popover>
  );
};

Собственно компонент Popover будет выглядеть следующим образом:

const PopoverContainer = ({ isOpen, content, children }) => {
	// Render the content only if the popover is open
	return (
		<div className="no-library">
			{children}
			{isOpen && content}
		</div>
	);
};

export default PopoverContainer;

Приведенный ниже GIF демонстрирует результат:

Хотя на данный момент эта демонстрация работает отлично, есть две существенные проблемы, которые могут возникнуть - размещение и обрезание - каждая из которых имеет множество потенциальных крайних случаев, которые необходимо решить. Давайте рассмотрим их сейчас.

Проблема размещения

В настоящее время элемент ссылки - представленный кнопкой в GIF выше - расположен по центру, поэтому всплывающее окно работает правильно. Однако, когда элемент находится у правого края браузера, это может привести к переполнению и необходимости прокрутки.

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

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

Проблемы с обрезанием

Непредсказуемо, куда может попасть многоразовый компонент popover. Он может оказаться внутри контейнера со стилями, которые могут нарушить работу всплывающего окна, например overflow: hidden или другие стили.

В таком случае, если элемент находится рядом с нижним краем границы, всплывающее окно будет усечено:

Мы можем включить всплывающее окно, чтобы оно появлялось за пределами родительского элемента и не учитывало overflow: hidden, используя React Portals:

import { createPortal } from 'react-dom';

const Popover = ({ isOpen, content, children }) => (
	<div>
		{children}
		{isOpen && createPortal(content, document.body)}
	</div>
);

export default Popover;

Функция createPortal позволяет нам вывести содержимое непосредственно в указанный узел DOM - в данном случае, внутри <body>.

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

Вместо того, чтобы тратить часы разработки на решение крайних случаев, давайте изучим выдающиеся библиотеки, которые помогают решить эти проблемы элегантным и производительным способом.

1. Popper.js: Механизм позиционирования всплывающих окон и всплывающих подсказок

Popper.js - это библиотека позиционирования, предназначенная для элементов, которые “всплывают”, включая всплывающие окна.

Технически Popper.js не является библиотекой попповеров сама по себе - нам все равно придется создавать попповер, как было показано ранее. Однако она значительно упрощает процесс создания надежных поповеров, справляясь со сложностями, связанными с размещением, переполнением и переворачиванием.

Благодаря его возможностям различные библиотеки пользовательского интерфейса, такие как Material UI, Foundation и Bootstrap, используют Popper.js для обеспечения точного позиционирования всплывающих элементов. Аналогично, разработчики React часто используют его в качестве основополагающего инструмента для создания пользовательских всплывающих окон.

Хотя Popper.js не является эксклюзивом React, он предоставляет обертку react-popper, облегчающую внедрение мощных возможностей позиционирования Popper в приложения React.

Теперь давайте рассмотрим, как библиотека Popper может помочь в непосредственном прикреплении всплывающего окна к кнопке ссылки.

Настройка Popper и его использование с порталами

Для начала установим @popperjs/core и его React-обертку:

npm i react-popper @popperjs/core

В предыдущем примере мы наблюдали, как функция createPortal отображает содержимое поповера в другой части DOM. Теперь давайте воспользуемся библиотекой Popper, чтобы точно решить проблему позиционирования.

Обертка react-popper предоставляет хук usePopper, который требует три аргумента: referenceElement, popperElement и объект конфигурации. В этой конфигурации мы можем указать начальное размещение всплывающего окна:

import { useState } from 'react';
import { usePopper } from 'react-popper';
import Popover from './Popover';
import Button from './Button';
import RxCaretSort from './RxCaretSort';

const TableRow = ({ name, email, popup }) => {
	const [referenceElement, setReferenceElement] = useState(null);
	const [popperElement, setPopperElement] = useState(null);
	const [isPopoverOpen, setIsPopoverOpen] = useState(false);

	const { styles, attributes } = usePopper(referenceElement, popperElement, {
		placement: 'bottom-start',
		modifiers: [
			{
				name: 'offset',
				options: {
					offset: [0, 5],
				},
			},
		],
	});

	return (
		<Popover
			isOpen={isPopoverOpen}
			content={
				<div
					ref={setPopperElement}
					style={styles.popper}
					{...attributes.popper}
					className="popover-content"
				>
					{popup}
				</div>
			}
		>
			<div
				className="btn-container"
				ref={setReferenceElement}
				onClick={() => setIsPopoverOpen(!isPopoverOpen)}
			>
				<Button label="Admin" />
				<RxCaretSort />
			</div>
		</Popover>
	);
};

export default TableRow;

Хук usePopper возвращает объект, содержащий стили и атрибуты, необходимые для позиционирования поповера вместе с элементом ссылки. Чтобы обеспечить правильное позиционирование, мы назначили сеттеры popper и reference на атрибуты ref как для содержимого popover, так и для элемента ссылки.

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

Использование react-popper без createPortal

Давайте посмотрим, как библиотека Popper управляет позиционированием без использования функции createPortal. Удалив ее из кода, мы получим следующее:

const Popover = ({ isOpen, content, children }) => {
	return (
		<div>
			{children}
			{isOpen && content}
		</div>
	);
};

export default Popover;

Благодаря возможности работы с контекстами offsetParent библиотека достаточно интеллектуальна, чтобы переместить содержимое popover в другое место, которое лучше подходит. Нет необходимости перемещать всплывающее окно за пределы его исходного контекста DOM:

Popper.js - отличный выбор, если вы хотите создать свой собственный popover, так как он способен управлять сложной, динамической логикой позиционирования без особых усилий. Однако если вы ищете готовый компонент popover с широкими возможностями, давайте рассмотрим следующую библиотеку.

2. react-tiny-popover: Легкая, но яркая библиотека

Если вы ищете простоту и минимальный след, react-tiny-popover станет отличным выбором. для конструирования попповеров.

Несмотря на свою легкость, эта библиотека надежна и предоставляет широкие возможности для настройки. Более того, по умолчанию она имеет отзывчивый дизайн, обеспечивающий совместимость с экранами разных размеров.

Установка и использование react-tiny-popover

Вы можете установить react-tiny-popover как есть, без каких-либо других зависимостей:

npm install react-tiny-popover -save

Использование этой библиотеки очень простое. Вместо того, чтобы создавать собственный компонент popover, эта библиотека предоставляет нам компонент, который мы можем непосредственно рендерить:

import { Popover } from 'react-tiny-popover';

const TableRow = ({ name, email, popup }) => {
	const [isPopoverOpen, setIsPopoverOpen] = useState(false);

	const togglePopover = () => {
		setIsPopoverOpen(!isPopoverOpen);
	};

	const renderPopoverContent = ({ position, childRect, popoverRect }) => (
		<ArrowContainer
			position={position}
			childRect={childRect}
			popoverRect={popoverRect}
			arrowColor={'#2a2e2d'}
			arrowSize={8}
		>
			<div>
				<div className="popover-content">{popup}</div>
			</div>
		</ArrowContainer>
	);

	return (
		<Popover
			isOpen={isPopoverOpen}
			positions={['top', 'bottom', 'left', 'right']}
			align="start"
			padding={8}
			onClickOutside={() => setIsPopoverOpen(false)}
			content={renderPopoverContent}
		>
			<div onClick={togglePopover} className="btn-container">
				<Button label="Admin" />
				<RxCaretSort />
			</div>
		</Popover>
	);
};

Компонент Popover из библиотеки требует три реквизита:

isOpen для отслеживания видимости children, который представляет элемент ссылки, в данном случае content, который принимает содержимое, которое будет отображаться в качестве всплывающего элемента

Ожидаемое поведение компонента Popover следующее:

Подобно возможностям позиционирования, предлагаемым Popper.js, react-tiny-popover также может защищаться от границ контейнера и перепозиционировать себя, чтобы предотвратить скрытое переполнение. Однако, в отличие от Popper, эта библиотека по умолчанию перемещает содержимое popover за пределы его DOM-контекста, добавляя его в document.body:

Чтобы расположить всплывающее окно рядом с кнопкой, которая его активирует, включите реквизит parentElement, а затем оберните Popover элементом ссылки:

import { useRef } from 'react';

const TableRow = ({ name, email }) => {
	const boxContainerRef = useRef();

	return (
		<div className="popover-container" ref={boxContainerRef}>
			<Popover parentElement={boxContainerRef.current}>{/* ... */}</Popover>
		</div>
	);
};

Теперь всплывающее окно должно быть прикреплено к элементу container, а не к элементу body:

Если вы предпочитаете всплывающее окно без стрелки, вы можете изменить реквизит content, чтобы исключить ArrowContainer, как показано ниже:

content={<div className="popover-content">{popup}</div>}

3. react-laag

react-laag предоставляет Hook для позиционирования всплывающих окон. Как и в случае с Popper.js, при создании визуальных аспектов всплывающего окна приходится приложить некоторые усилия. Библиотека берет на себя сложные вычисления для достижения точного позиционирования.

В последнее время ее популярность растет: с менее чем 50 тысяч еженедельных загрузок на npm до более чем 138 тысяч за последний год:

Настройка и использование react-laag

Как и react-tiny-popover, вы можете установить react-laag с нулевыми зависимостями:

npm install react-laag

Вот быстрый пример интеграции библиотеки в наш проект:

import { useState } from 'react';
import { useLayer, Arrow } from 'react-laag';

const TableRow = ({ name, email, popup }) => {
	const [isOpen, setIsOpen] = useState(false);

	const { renderLayer, triggerProps, layerProps, arrowProps } = useLayer({
		isOpen,
		onOutsideClick: () => setIsOpen(false),
		onDisappear: () => setIsOpen(false),
		overflowContainer: false,
		auto: true,
		placement: 'right-start',
		triggerOffset: 12,
		arrowOffset: 16,
	});

	const handleClick = () => {
		setIsOpen(!isOpen);
	};

	return (
		<Popover
			isOpen={isOpen}
			content={renderLayer(
				<div className="popover-content" {...layerProps}>
					{popup}
					<Arrow {...arrowProps} backgroundColor="#2a2e2d" />
				</div>,
			)}
		>
			<div {...triggerProps} onClick={handleClick} className="btn-container">
				<Button label="Admin" />
				<RxCaretSort />
			</div>
		</Popover>
	);
};

Несмотря на свой приНе обращая внимания на позиционирование, эта библиотека предоставляет важные функции всплывающего окна, такие как функция onOutsideClick для управления событием внешнего щелчка, которое закрывает всплывающее окно. Посмотрите на ожидаемое поведение в демонстрационном примере ниже:

Библиотека всплывающих окон reactjs-popup - отличный выбор для тех, кто ищет универсальность в простом пакете. Она предлагает полностью доступный компонент всплывающего окна, улучшая пользовательский опыт для тех, кто полагается на навигацию с помощью клавиатуры.

Настройка и использование reactjs-popup

Установка reactjs-popup не представляет собой ничего сложного. Просто используйте эту команду:

npm i reactjs-popup

Приведенный ниже код демонстрирует, как можно создать всплывающее окно с помощью reactjs-popup:

import React from 'react';
import Popup from 'reactjs-popup';
import Button from './Button';
import RxCaretSort from './RxCaretSort';

const TableRow = ({ name, email, popupContent }) => {
	return (
		<Popup
			trigger={
				<div className="btn-container">
					<Button label="Admin" />
					<RxCaretSort />
				</div>
			}
			position={['top left', 'top right', 'bottom left', 'bottom right']}
			closeOnDocumentClick
			arrowStyle={{ color: '#2a2e2d' }}
		>
			<div className="popover-content">{popupContent}</div>
		</Popup>
	);
};

Это самая простая реализация popover для нашего гипотетического проекта, которую мы видели до сих пор. reactjs-popup предоставляет нам простой в использовании компонент Popup и очень хорошо справляется со сложным позиционированием. Не стесняйтесь изучать исходный код и демонстрацию на CodeSandbox.

5. React Joyride: Экскурсии с помощью всплывающих окон

React Joyride использует уникальный подход к popovers, специализируясь на popovers, предназначенных для проведения экскурсий в приложениях React. Это отличный выбор для динамичного и увлекательного знакомства с новыми пользователями.

Прежде чем внедрять эту библиотеку, давайте посмотрим, как она работает:

Как мы видим, React Joyride обеспечивает достаточный контроль над позиционированием всплывающих окон, чтобы обеспечить плавную работу пользователя. Он может адаптироваться к разным размерам экрана, что делает его идеальным для создания онбординга.

Настройка и использование React Joyride

Установка React Joyride очень проста и требует только выполнения следующей команды без каких-либо других зависимостей:

npm i react-joyride

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

import React from 'react';
import Joyride from 'react-joyride';

const TableRow = ({ name, email, popup }) => {
	const [{ run, steps }] = React.useState({
		run: true,
		steps: [
			{
				content: <h2>Take a look at this application with me!</h2>,
				locale: { skip: <strong>SKIP</strong> },
				placement: 'center',
				target: 'body',
			},
			{
				content: <h2>User Data</h2>,
				placement: 'bottom',
				target: '.user',
			},
			{
				content: <h2>Assign Role</h2>,
				placement: 'bottom',
				target: '.btn-container',
			},
			{
				content: <h2>Take me to the next section</h2>,
				placement: 'bottom',
				target: '.navigation',
			},
		],
	});

	return (
		<>
			<Joyride
				steps={steps}
				continuous
				hideCloseButton
				run={run}
				scrollToFirstStep
				showProgress
				showSkipButton
			/>
			{/*...*/}
		</>
	);
};

Сравнительная таблица библиотек всплывающих окон React

Эта сравнительная таблица для всех пяти библиотек всплывающих окон может оказаться полезным ресурсом, когда вы будете решать, какой вариант лучше всего подойдет для вашего проекта:

Назначение библиотекиПопулярностьСообществоЛучшее для
Popper.js29,6K звезд GitHub,Активные и поддерживающие приложения, требующие точного позиционирования элементов пользовательского интерфейса
12 миллионов еженедельных загрузок с npm
react-tiny-popover405 звезд GitHub,Активное сообществоПроекты, требующие простого и настраиваемого решения для создания всплывающих окон
93,5K еженедельных загрузок npm
react-laag884 звезды GitHub,Активное сообществоПроекты, требующие точного контроля над позиционированием всплывающих окон
138K еженедельных загрузок npm
reactjs-popup1.7k GitHub stars,Активное сообществоПроекты, требующие универсального и настраиваемого решения для создания всплывающих окон
110K еженедельных загрузок npm
React Joyride6k GitHub stars,Активные проекты сообществаПроекты, требующие интерактивного опыта онбординга

Заключение

Поповеры - это интерактивный и удобный способ улучшить ваши React-приложения, но их может быть сложно реализовать с нуля. Библиотеки Popover могут облегчить решение различных проблем, чтобы ваши компоненты popover выглядели и работали отлично на любом устройстве или размере экрана.

В обширном ландшафте библиотек всплывающих окон React, выборce сводится к конкретным потребностям вашего проекта. Если вы стремитесь к легковесной простоте reactjs-popup и react-tiny-popover или к надежным возможностям позиционирования Popper.js, вы можете выбрать из множества вариантов.

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

В конце концов, путешествие по этим библиотекам не только улучшит ваши навыки работы с React, но и позволит вам создавать привлекательные и удобные всплывающие интерфейсы.