Как стать автором
Обновить
2003.71
МТС
Про жизнь и развитие в IT

Полезные библиотеки для React-приложений в 2025 году: на что обратить внимание

Время на прочтение11 мин
Количество просмотров4.3K

Привет, Хабрчане! Это Леша Жиряков, техлид backend-команды витрины KION. В прошлый раз я писал о секретах популярности Python, а сегодня будет пост о разработке на React. Расскажу, какие библиотеки стоит добавить в свой набор в 2025 году, приведу плюсы и минусы каждой, данные с GitHub и примеры использования. Начнем!

Tremor

Tremor — UI-библиотека для создания дашбордов и аналитических интерфейсов в React. В отличие от инструментов, заточенных исключительно на визуализации данных, Tremor предлагает готовые UI-компоненты: карточки, таблицы, кнопки, графики, фильтры и так далее. Библиотека построена на Tailwind CSS (об этом в блоге писал коллега), так что она удобна для кастомизации.

Главная идея Tremor — ускорить разработку дашбордов, предоставив хорошо стилизованные и адаптивные компоненты. Например, можно за несколько строк кода создать карточку с ключевой метрикой или быстро интегрировать диаграмму из Recharts, Nivo или ECharts. Поддерживается темная и светлая темы, предусмотрена адаптация к разным экранам.

Плюсы:

  • готовые UI-компоненты, сокращающие время разработки;

  • легкая интеграция с Recharts, Nivo и ECharts;

  • гибкость благодаря Tailwind CSS.

Минусы:

  • ограниченная кастомизация в сравнении с чистыми UI-фреймворками;

  • не предназначен для сложных и нестандартных интерфейсов.

GitHub:

  • количество звезд: 2,1 тыс.;

  • открытых Issues: 11;

  • год релиза: 2024;

  • Merge Requests (MRs): разработчики проекта и сообщество.

Отличный выбор, если нужно быстро развернуть дашборд с минимальными усилиями, но для более детальной настройки могут потребоваться другие UI-библиотеки.

Еще о сильных сторонах

Tremor содержит в себе множество готовых компонентов: графики (Area Chart, Bar Chart, Donut Chart, Progress Bar), элементы для ввода (Calendar, Checkbox, Date Picker, Radio Card Group) и другие UI-элементы (Badge, Button, Dialog, Table).

Например, мы хотим добавить кнопку (Button). В документации Tremor весь код уже написан: Ctrl + C, Ctrl + V — и вперед!

Устанавливаем зависимости:

npm install @radix-ui/react-slot tailwind-variants @remixicon/react

Добавляем код в директорию проекта, где хранятся компоненты. Важно не забыть обновить импорты:

// Tremor Button [v0.2.0]

import React from "react"
import { Slot } from "@radix-ui/react-slot"
import { RiLoader2Fill } from "@remixicon/react"
import { tv, type VariantProps } from "tailwind-variants"


import { cx, focusRing } from "@/lib/utils"


const buttonVariants = tv({
 base: [
   // base
   "relative inline-flex items-center justify-center whitespace-nowrap rounded-md border px-3 py-2 text-center text-sm font-medium shadow-sm transition-all duration-100 ease-in-out",
   // disabled
   "disabled:pointer-events-none disabled:shadow-none",
   // focus
   focusRing,
 ],
 variants: {
   variant: {
     primary: [
       // border
       "border-transparent",
       // text color
       "text-white dark:text-white",
       // background color
       "bg-blue-500 dark:bg-blue-500",
       // hover color
       "hover:bg-blue-600 dark:hover:bg-blue-600",
       // disabled
       "disabled:bg-blue-300 disabled:text-white",
       "disabled:dark:bg-blue-800 disabled:dark:text-blue-400",
     ],
     secondary: [
       // border
       "border-gray-300 dark:border-gray-800",
       // text color
       "text-gray-900 dark:text-gray-50",
       // background color
       "bg-white dark:bg-gray-950",
       //hover color
       "hover:bg-gray-50 dark:hover:bg-gray-900/60",
       // disabled
       "disabled:text-gray-400",
       "disabled:dark:text-gray-600",
     ],
     light: [
       // base
       "shadow-none",
       // border
       "border-transparent",
       // text color
       "text-gray-900 dark:text-gray-50",
       // background color
       "bg-gray-200 dark:bg-gray-900",
       // hover color
       "hover:bg-gray-300/70 dark:hover:bg-gray-800/80",
       // disabled
       "disabled:bg-gray-100 disabled:text-gray-400",
       "disabled:dark:bg-gray-800 disabled:dark:text-gray-600",
     ],
     ghost: [
       // base
       "shadow-none",
       // border
       "border-transparent",
       // text color
       "text-gray-900 dark:text-gray-50",
       // hover color
       "bg-transparent hover:bg-gray-100 dark:hover:bg-gray-800/80",
       // disabled
       "disabled:text-gray-400",
       "disabled:dark:text-gray-600",
     ],
     destructive: [
       // text color
       "text-white",
       // border
       "border-transparent",
       // background color
       "bg-red-600 dark:bg-red-700",
       // hover color
       "hover:bg-red-700 dark:hover:bg-red-600",
       // disabled
       "disabled:bg-red-300 disabled:text-white",
       "disabled:dark:bg-red-950 disabled:dark:text-red-400",
     ],
   },
 },
 defaultVariants: {
   variant: "primary",
 },
})


interface ButtonProps
 extends React.ComponentPropsWithoutRef<"button">,
   VariantProps<typeof buttonVariants> {
 asChild?: boolean
 isLoading?: boolean
 loadingText?: string
}


const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
 (
   {
     asChild,
     isLoading = false,
     loadingText,
     className,
     disabled,
     variant,
     children,
     ...props
   }: ButtonProps,
   forwardedRef,
 ) => {
   const Component = asChild ? Slot : "button"
   return (
     <Component
       ref={forwardedRef}
       className={cx(buttonVariants({ variant }), className)}
       disabled={disabled || isLoading}
       tremor-id="tremor-raw"
       {...props}
     >
       {isLoading ? (
         <span className="pointer-events-none flex shrink-0 items-center justify-center gap-1.5">
           <RiLoader2Fill
             className="size-4 shrink-0 animate-spin"
             aria-hidden="true"
           />
           <span className="sr-only">
             {loadingText ? loadingText : "Loading"}
           </span>
           {loadingText ? loadingText : children}
         </span>
       ) : (
         children
       )}
     </Component>
   )
 },
)


Button.displayName = "Button"


export { Button, buttonVariants, type ButtonProps }

Используем такой блок кода:

import { Button } from '@/components/Button';
 export const ButtonHero = () => (
 <div className="flex justify-center">
   <Button asChild>
     <a href="#hello">Hello, Habr!</a>
   </Button>
 </div>
);

Готово! Получаем следующую кнопку:

Planby

Специализированный React-компонент для отображения таймлайнов, расписаний и диаграмм Ганта. В отличие от универсальных библиотек визуализации вроде Recharts или Nivo, Planby заточен именно под временные шкалы и позволяет эффективно рендерить большие объемы данных.

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

Плюсы:

  • гибкость в кастомизации отображения событий;

  • поддержка горизонтальной прокрутки и масштабирования.

Минусы:

  • подходит только для таймлайнов и расписаний;

  • ограниченная документация и сравнительно небольшое сообщество;

  • может потребовать дополнительных стилей для полной адаптации под дизайн системы.

GitHub:

  • Количество звезд: 1,5 тыс.

  • Открытых Issues: 6.

  • Версия: 1.1.7.

  • Год релиза: 2022.

  • Merge Requests (MRs): главный разработчик и сообщество. Сейчас открытых MRs и нет, последние изменения вносились в проект два года назад.

Если нужно отобразить расписание, временную диаграмму или диаграмму Ганта в React, Planby — одно из лучших решений.

Еще о сильных сторонах

Есть три способа, как можно использовать Planby.

Стандартный шаблон:

import { useEpg, Epg, Layout } from 'planby';

const channels = React.useMemo(
  () => [
    {
      logo: 'https://via.placeholder.com',
      uuid: '10339a4b-7c48-40ab-abad-f3bcaf95d9fa',
      ...
    },
  ],
  []
);

const epg = React.useMemo(
  () => [
    {
      channelUuid: '30f5ff1c-1346-480a-8047-a999dd908c1e',
      description:
        'Ut anim nisi consequat minim deserunt...',
      id: 'b67ccaa3-3dd2-4121-8256-33dbddc7f0e6',
      image: 'https://via.placeholder.com',
      since: "2022-02-02T23:50:00",
      till: "2022-02-02T00:55:00",
      title: 'Title',
      ...
    },
  ],
  []
);

const {
  getEpgProps,
  getLayoutProps,
  onScrollToNow,
  onScrollLeft,
  onScrollRight,
} = useEpg({
  epg,
  channels,
  startDate: '2022/02/02', // or 2022-02-02T00:00:00
});

return (
  <div>
    <div style={{ height: '600px', width: '1200px' }}>
      <Epg {...getEpgProps()}>
        <Layout
          {...getLayoutProps()}
        />
      </Epg>
    </div>
  </div>
);

Настройка ширины и высоты:

const {
  getEpgProps,
  getLayoutProps,
  ...
} = useEpg({
  epg,
  channels,
 startDate: '2022/02/02', // or 2022-02-02T00:00:00
  width: 1200,
  height: 600
});

return (
  <div>
     <Epg {...getEpgProps()}>
        <Layout
          {...getLayoutProps()}
        />
      </Epg>
  </div>

Настройка временного диапазона:

const {
  getEpgProps,
  getLayoutProps,
  ...
} = useEpg({
  epg,
  channels,
  startDate: '2022-02-02T10:00:00',
  endDate: '2022-02-02T20:00:00',
  width: 1200,
  height: 600
});

return (
  <div>
     <Epg {...getEpgProps()}>
        <Layout
          {...getLayoutProps()}
        />
      </Epg>
  </div>

Так выглядит горизонтальный скролл:

React DnD

React DnD — библиотека для реализации Drag & Drop в React на основе HTML5 API. Позволяет настраивать перетаскивание элементов через React-компоненты, упрощая код. Еще одно достоинство — гибкость и высокая производительность.

В отличие от более простых решений, таких как react-beautiful-dnd, библиотека предлагает гибкую систему декораторов (useDrag и useDrop) и контекстов, так что она универсальнее. React DnD поддерживает сложные сценарии перетаскивания, включая вложенные иерархии, перенос элементов между разными списками и обработку состояния в Redux.

Плюсы:

  • легковесная, интегрируется с React;

  • гибкость — можно настраивать практически любые сценарии;

  • хорошая поддержка и документация.

Минусы:

  • сложнее в освоении, чем react-beautiful-dnd;

  • требует работы с useDrag и useDrop, что может быть непривычно.

GitHub:

  • количество звезд: 21,3 тыс.;

  • открытых Issues: 435;

  • версия: 16.0.0;

  • год релиза: 2014;

  • Merge Requests (MRs): основные разработчики и сообщество.

Если нужен гибкий и мощный инструмент для Drag & Drop, React DnD — отличный выбор. Но если задача ограничивается перетаскиванием элементов в списке, лучше использовать react-beautiful-dnd.

Еще о сильных сторонах

В React DnD два основных компонента: DndProvider и DragPreviewImage, — которые позволяют реализовывать различные сценарии.

DndProvider — предоставляет возможности React-DnD для приложения. Должен быть интегрирован в бэкенд через свойство backend, а еще может быть добавлен с помощью объекта window.

Пример использования:

import { HTML5Backend } from 'react-dnd-html5-backend'
import { DndProvider } from 'react-dnd'

export default class YourApp {
  render() {
    return (
      <DndProvider backend={HTML5Backend}>
        /* Ваше Drag-and-Drop приложение */
      </DndProvider>
    )
  }
}

DragPreviewImage — компонент, который отрисовывает HTML-изображение в качестве отсоединяемого перетаскиваемого предварительного просмотра:

import { DragSource, DragPreviewImage } from 'react-dnd'

function DraggableHouse({ connectDragSource, connectDragPreview }) {
  return (
    <>
      <DragPreviewImage src="sun_dragged.png" connect={connectDragPreview} />
      <div ref={connectDragSource}>☀️</div>
    </>
  )
}
export default DragSource(
  /* ... */
  (connect, monitor) => ({
    connectDragSource: connect.dragSource(),
    connectDragPreview: connect.dragPreview()
  })
)

Advanced Cropper

Advanced Cropper — библиотека для точного кадрирования изображений в React. Она дает гибкие инструменты для масштабирования, вращения, зума и ограничения областей обрезки. Поддерживаются touch-жесты, что пригодится для мобильных устройств.

Главное преимущество Advanced Cropper — высокая точность и возможность глубокой кастомизации. Можно задавать фиксированные пропорции, управлять ограничениями области обрезки и добавлять пользовательские элементы управления. Библиотека поддерживает canvas-отрисовку, что делает ее производительной даже при работе с большими изображениями.

Плюсы:

  • поддержка зума, вращения и ограничения области обрезки;

  • гибкость: можно настраивать взаимодействие и UI под свои нужды;

  • хорошо адаптирован для мобильных устройств.

Минусы:

  • требует работы с canvas, если нужна глубокая кастомизация;

  • не самый легковесный вариант.

GitHub:

  • количество звезд: 763; 

  • открытых Issues: 23;

  • версия: 0.20.1;

  • год релиза: 2021;

  • Merge Requests (MRs): главный разработчик и сообщество.

Если в проекте требуется продвинутая обрезка изображений с точными настройками, Advanced Cropper — отличный выбор. 

Еще о сильных сторонах

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

import React, { useState } from 'react';
import { CropperRef, Cropper } from 'react-advanced-cropper';
import 'react-advanced-cropper/dist/style.css'

export const GettingStartedExample = () => {
    const [image, setImage] = useState(
'https://cdn.prod.website-files.com/65cb50148a423f63add18bc6/65ce1bf224944099ef1159b3_habr.png',
    );

    const onChange = (cropper: CropperRef) => {
        console.log(cropper.getCoordinates(), cropper.getCanvas());
    };

    return (
        <Cropper
            src={image}
            onChange={onChange}
            className={'cropper'}
        />
    )
};

На колесико мыши работает зум:

React Resizable Panels

React Resizable Panels — библиотека для создания изменяемых по размеру панелей в React-приложениях. Позволяет перетаскивать границы между панелями, менять их ширину или высоту. Отмечу еще гладкие анимации и отзывчивый интерфейс.

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

Плюсы:

  • простая интеграция и декларативный API;

  • поддержка горизонтального и вертикального изменения размеров;

  • хорошо работает с анимациями и адаптивным дизайном.

Минусы:

  • подходит только для работы с панелями, для сложных лейаутов может потребоваться CSS Grid или Flexbox.

GitHub:

  • количество звезд: 4,3 тыс.;

  • открытых Issues: 17;

  • версия: 2.1.7;

  • год релиза: 2022;

  • Merge Requests (MRs): главный разработчик и сообщество.

Если нужно удобное изменение размеров панелей без боли, React Resizable Panels — хорошее решение. Оно идеально для редакторов кода, дашбордов и приложений с гибкой компоновкой.

Еще о сильных сторонах

В React Resizable Panels можно создать горизонтальный и вертикальный макеты. Сначала о первом:

<PanelGroup direction="horizontal">
 <Panel defaultSize={30} minSize={20}>
   left
 </Panel>
 <PanelResizeHandle />
 <Panel minSize={30}>
   middle
 </Panel>
 <PanelResizeHandle />
 <Panel defaultSize={30} minSize={20}>
   right
 </Panel>
</PanelGroup>

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

Теперь про вертикальный:

<PanelGroup direction="vertical">
 <Panel maxSize={75}>
   top
 </Panel>
 <PanelResizeHandle />
 <Panel maxSize={75}>
   bottom
 </Panel>
</PanelGroup>

Принцип работы тут похожий:

ShadCN UI

ShadCN UI — коллекция UI-компонентов для React, созданная поверх Radix UI и стилизованная с помощью Tailwind CSS. В отличие от традиционных библиотек компонентов (например, MUI или Ant Design), ShadCN не поставляется как отдельный npm-пакет, а предлагает компоненты в виде кода, который можно скопировать в свой проект и кастомизировать.

Главная идея ShadCN UI — гибкость и контроль. Вместо жестко заданных стилей и ограничений — готовые элементы, их легко адаптировать под дизайн системы. Они выглядят минималистично и отлично вписываются в проекты, использующие Tailwind CSS. В библиотеке есть кнопки, поля ввода, диалоги, таблицы, дропдауны и другие базовые элементы UI.

Плюсы:

  • полный контроль над кодом компонентов, их можно редактировать под себя;

  • использует Radix UI, что дает доступность (a11y) и хорошую семантику;

  • отлично совместим с Tailwind CSS;

  • минималистичный дизайн, легко адаптировать под кастомный UI.

Минусы:

  • нужно вручную копировать и поддерживать компоненты в проекте;

  • не такая богатая экосистема, как у Ant Design или MUI;

  • может не подойти, если нужен полный набор готовых решений «из коробки».

GitHub:

  • количество звезд: 83,6 тыс.;

  • открытых Issues: 840;

  • версия: 2.3.0;

  • год релиза: 2023;

  • Merge Requests (MRs): основные разработчики и сообщество. 

ShadCN UI — хороший выбор для тех, кто хочет гибкость Tailwind CSS, удобство Radix UI и контроль над кодом компонентов. Это отличный вариант для кастомных дизайн-систем и современных React-приложений.

Еще о сильных сторонах

В ShadCN UI имеется целый набор готовых компонентов: Accordion (не музыкальный инструмент аккордеон, а вертикально расположенный набор интерактивных заголовков, в каждом из которых находится свой контент), Alert, Card, Chart, Checkbox, Data Table, Dialog, Drawer, Menubar и другие.

Чтобы создать Menubar, необходимо добавить импорты:

import {  
Menubar,  
MenubarContent,  
MenubarItem,  
MenubarMenu,  
MenubarSeparator,  
MenubarShortcut,  
MenubarTrigger,
} from "@/components/ui/menubar"

И использовать такую структуру:

<Menubar>  
  <MenubarMenu>    
    <MenubarTrigger>File</MenubarTrigger>    
    <MenubarContent>      
      <MenubarItem>        
        New Tab <MenubarShortcut>⌘T</MenubarShortcut>      
      </MenubarItem>      
      <MenubarItem>New Window</MenubarItem>    
      <MenubarSeparator />     
      <MenubarItem>Share</MenubarItem>      
      <MenubarSeparator />      
      <MenubarItem>Print</MenubarItem>    
    </MenubarContent>  
  </MenubarMenu>
</Menubar>

Пример, как выглядит компонент Menubar:

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

Теги:
Хабы:
Всего голосов 30: ↑29 и ↓1+35
Комментарии1

Полезные ссылки

FreeIPA: как обнаружить атаку злоумышленника на любом этапе Kill Chain

Время на прочтение13 мин
Количество просмотров1.1K
Всего голосов 4: ↑4 и ↓0+6
Комментарии0

Jetpack Compose для Android TV: как происходит перемещение фокуса

Время на прочтение10 мин
Количество просмотров952
Всего голосов 3: ↑3 и ↓0+5
Комментарии0

Обходим подводные камни работы с UDA в коде на Lua для ScyllaDB: дружим Java-драйвер и пустые значения

Уровень сложностиСредний
Время на прочтение5 мин
Количество просмотров489
Всего голосов 5: ↑5 и ↓0+10
Комментарии0

Интеграция виджета обратного звонка МТС Exolve в документацию на MkDocs

Время на прочтение8 мин
Количество просмотров432
Всего голосов 5: ↑5 и ↓0+7
Комментарии0

Путь видео в онлайн-кинотеатрах от «стекла до стекла». Middleware — ядро, подписки, сервисы, витрина

Уровень сложностиПростой
Время на прочтение7 мин
Количество просмотров824
Всего голосов 4: ↑3 и ↓1+4
Комментарии0

Информация

Сайт
www.mts.ru
Дата регистрации
Дата основания
Численность
свыше 10 000 человек
Местоположение
Россия