Библиотеки React drag and drop для досок и списков
Библиотеки React drag and drop отличаются сильнее, чем кажется по демо. Перед выбором сравните поддержку touch, вложенные макеты и собственное поведение.

Почему с этим выбором быстро становится сложно
Простой сортируемый список кажется легкой задачей. Вы берете элемент, двигаете его вверх или вниз и сохраняете новый порядок. Но kanban-доска на React — это уже другая история. Карточки перемещаются внутри колонки, между колонками и иногда между отфильтрованными представлениями. Библиотека, которая выглядит плавно в простом демо, может начать вести себя неловко, как только макет перестает быть плоским.
Именно поэтому drag and drop-библиотеки сложно оценить по скриншотам или коротким примерам. В большинстве демо показывают десять блоков на экране компьютера с идеальными отступами. В реальных продуктах есть sticky-заголовки, длинные карточки, автоскролл, пустые колонки и пользователи, которые перетаскивают слишком быстро.
На телефонах появляется еще один уровень сложности. Touch drag and drop часто конфликтует с обычным скроллом страницы, особенно если доска находится внутри прокручиваемой области. Если пользователь пытается пролистать страницу, а приложение начинает перетаскивать элемент, сразу возникает ощущение, что все сломано. Если приложение слишком долго ждет перед началом drag, оно кажется медленным. На мобильных даже маленькие решения по таймингу имеют значение.
Вложенные макеты повышают сложность еще сильнее. В планировщике могут быть swimlanes, у каждой дорожки — свои колонки, а в каждой колонке — карточки с handle, меню и полями ввода. Дальше правила начинают накапливаться: какие-то карточки можно двигать куда угодно, какие-то только внутри одной дорожки, какие-то группы можно сортировать, а какие-то нельзя. Каждое правило звучит мелко, пока вы не попробуете совместить его со всеми остальными.
Вот где polished-демо вводят в заблуждение. Пакет может выглядеть аккуратно, если он решает один удачный сценарий. Проблемы появляются позже, когда вам нужны собственные правила столкновения, лучшее поведение клавиатуры, более плавная поддержка touch или превью перетаскивания, которое не дергается.
Что сравнить перед выбором пакета
Сначала смотрите на структуру интерфейса, а не на название пакета. У простого sortable list совсем другие требования, чем у kanban-доски на React с колонками или у планировщика со swimlanes, датами и карточками, которые двигаются по нескольким осям. Если вам еще и нужен tree view, nested drag and drop быстро становится сложным.
Библиотека может отлично выглядеть в демо и все равно начать мешать, когда появляются реальные правила. Оценивать React drag and drop-библиотеки проще, если сначала записать, какой именно макет вам нужен: список, доска, planner, дерево или их смесь.
Затем рано тестируйте способы ввода. Поддержка мыши обычно самая простая. А вот touch drag and drop — это то, где многие инструменты начинают вести себя неловко, особенно на планшетах. Поддержка клавиатуры тоже важна, если людям нужно доступное переставление элементов без мыши.
Перед сравнением API сначала запишите, что именно смогут делать пользователи. Могут ли они сортировать элементы в одном списке, переносить карточки между колонками, копировать вместо перемещения, группировать элементы или запрещать drop в некоторых местах? Эти правила определяют всю реализацию.
Пустые колонки — частая ловушка. Одни библиотеки обрабатывают их аккуратно, другим нужен дополнительный код только для того, чтобы пользователь мог бросить элемент в пустое место. То же самое касается заблокированных drop, фиксированных карточек и правил вроде «только менеджеры могут перемещать этот элемент».
Еще стоит оценить, сколько собственной логики ваша команда сможет поддерживать без боли. Небольшая команда спокойно справится с несколькими правилами drop и одним кастомным превью. Но становится тяжело, когда приложению нужны вложенные контейнеры, исправления для touch, тонкая настройка автоскролла и отдельные исключения для каждой колонки.
Если ваше приложение останется близко к обычному sortable list, подойдут многие варианты. Но если продукт уже полон исключений, выбирайте инструмент, который остается предсказуемым под нагрузкой, даже если первое демо выглядит менее эффектно.
Основные варианты, к которым обычно приходят
Большинство React drag and drop-библиотек выглядят похожими, пока вы не начнете строить что-то чуть более необычное. Плоский список — это просто. Доска с поддержкой touch, вложенными зонами, автоскроллом и собственными правилами drop — вот где различия становятся заметны.
dnd-kit — это пакет, который многие команды пробуют первым. Он хорошо работает с мышью, клавиатурой и touch, а его инструменты сортировки позволяют быстро запустить доску без большой настройки. Компромисс — контроль. Когда вам нужны nested drag and drop, собственные правила столкновения или перемещения в стиле planner между неровными контейнерами, обычно приходится писать довольно много вручную.
React DnD дает больше контроля с самого начала. Это полезно, когда карточки, колонки, боковые панели и необычные drop-targets требуют разных правил. Он мощный, но ощущается более низкоуровневым. Для обычного kanban-доски на React он может казаться слишком «проводным» решением для задачи, которая звучала просто.
react-beautiful-dnd задал стандарт для перемещения в стиле доски, а поддерживаемые форки вроде @hello-pangea/dnd по-прежнему хорошо подходят для такого типа интерфейса. Если ваше приложение — это, по сути, списки внутри списков, работать с ним приятно. Но как только макет перестает быть линейным, начинают проявляться слабые места. Сетки, глубокая вложенность и необычные ограничения быстро усложняют жизнь.
Нативный HTML drag and drop по-прежнему важен как базовый вариант. Он ничего не стоит и может подойти для десктопного инструмента. Но поддержка touch там неровная, а такие детали, как превью перетаскивания и обратная связь при сортировке, обычно становятся вашей задачей.
Старые пакеты вроде react-sortable-hoc до сих пор встречаются в туториалах. Они могут работать, но часто приносят больше ограничений, больше патчей и больше времени на борьбу с библиотекой вместо создания самой функции.
Как touch-поддержка меняет результат
Пакет, который на мыши ощущается нормально, на телефоне может казаться сломанным. И это меняет весь выбор, особенно если речь о kanban-доске на React или sortable lists React, с которыми пользователи работают каждый день.
Эмуляции на десктопе недостаточно. Проверяйте на настоящем телефоне, большим пальцем, в движении, во время скролла и при переключении между короткими и длинными списками. Именно тогда быстро всплывают мелкие проблемы.
Длинные списки — место, где многие библиотеки начинают вести себя неловко. Если пользователь пытается прокрутить список, а библиотека начинает drag вместо скролла, доска раздражает уже через несколько минут. Если для начала drag нужен долгий тап, это может помочь, но только если задержка ощущается естественной, а не тормозной.
Небольшой drag handle часто заметно улучшает touch-поведение. Он дает пользователю одну понятную точку захвата, так что можно по-прежнему нажимать на карточки, открывать меню и прокручивать список без случайного перемещения элемента. Без handle каждая карточка становится ловушкой.
Короткий тест на телефоне должен ответить на несколько простых вопросов. Drag начинается по нажатию, по удержанию или после короткого движения? Можно ли прокрутить длинную колонку, не запуская drag? Можно ли нажимать кнопки внутри элемента? Что происходит, когда палец доходит до края экрана?
Последний вопрос важнее, чем многие думают. На реальной доске пользователи перетаскивают элементы к верхнему или нижнему краю, а список при этом должен продолжать скроллиться. Одни библиотеки делают edge scrolling плавно. Другие зависают, дергаются или бросают элемент не туда.
Если выбираете между пакетами, доверяйте тому, который на мобильных ощущается скучно и предсказуемо. Плавный скролл, понятный старт drag и аккуратные handle выигрывают у эффектных демо каждый раз.
Вложенные макеты быстро показывают слабые места
Плоский sortable list может заставить большинство библиотек выглядеть хорошо. Добавьте колонки, пустые дорожки и вложенные элементы — и слабые места быстро всплывут.
Начните с базового перемещения в доске: перетащите карточку из одной колонки в другую, а потом верните обратно. Одни библиотеки хорошо сортируют внутри одного списка, но начинают вести себя странно, когда элементы прыгают между контейнерами. Появляются странные ошибки индексов, дергающееся превью или карточки, которые на кадр возвращаются назад, прежде чем встать на место.
Пустые колонки — распространенная ловушка. Хорошая библиотека позволяет бросить элемент в пустую дорожку без фейковых spacer-элементов или невидимых целей. Если для того, чтобы пустая колонка приняла одну карточку, нужны хаки, значит дальше все обычно станет еще сложнее.
Вложенные макеты повышают сложность еще сильнее. Планировщик со swimlanes, карточками и маленькими подэлементами внутри каждой карточки звучит нормально, но зоны drop родителя и ребенка часто начинают мешать друг другу. Один слой хочет сортировать дорожку. Другой хочет сортировать чеклист внутри карточки. Если библиотека не дает четкого контроля над drag-handle, sensors и collision rules, вам придется писать много защитного кода.
Визуальная часть не менее важна. В глубоких структурах placeholders могут растягивать карточки, отступы могут схлопываться, а автоскролл — выбирать не тот контейнер. В демо это кажется мелочью. В реальной доске это делает весь интерфейс ненадежным.
Короткий тест показывает большую часть проблем. Сделайте один экран с тремя колонками, одной пустой колонкой, карточками, которые перемещаются между колонками, одной карточкой с подэлементами, которые можно сортировать, и достаточным количеством контента, чтобы включился скролл. Потом попробуйте это мышью и на телефоне. Для nested drag and drop это скажет больше, чем любой список функций.
Когда собственное поведение начинает мешать
Взаимодействие drag кажется простым, пока у доски не появляются правила. Тогда библиотека перестает быть удобной UI-помощью и начинает влиять на сам продукт.
Первую боль обычно вызывает бизнес-логика. Команда хочет, чтобы выполненные карточки были заблокированы и никто не мог вернуть их обратно. Шаблонные карточки должны копироваться в колонку, а не перемещаться. Некоторые drop должны работать только для менеджеров, только когда колонка открыта или только если тип элемента совпадает с целью.
Многие React drag and drop-библиотеки умеют это делать, но цена быстро меняется. Если правила можно выразить в одном обработчике drag — это нормально. Если нужны собственные sensors, ручные патчи состояния и дополнительный код для исправления визуальных сбоев после каждого drop, значит библиотека уже начинает вам мешать.
Небольшой planner показывает это особенно хорошо. Допустим, у вас есть swimlanes для дизайна, разработки и QA. Менеджер перетаскивает шаблон задачи в разработку, и там должна создаваться копия. Разработчик перетаскивает закрытый баг, и он должен оставаться заблокированным в done. QA-lead открывает меню карточки во время drag, а чекбокс внутри карточки все равно должен работать. Вот на такой смеси простые демо и ломаются.
Проблемы обычно видно заранее. Если вы пишете больше защитного кода, чем кода самого drag, если клики и inline-редактирование ломаются, как только начинается перетаскивание, если одной колонке постоянно нужен особый подход или если интерфейс мигает и показывает неправильный placeholder, стоимость уже растет.
Собственное поведение — это не только про правила. Это еще и про то, сколько кода вокруг библиотеки вам приходится поддерживать. Считайте обертки, исправления событий, преобразования состояния и тесты, которые нужны, чтобы доверять одному перемещению.
Если пакет экономит 50 строк в первый день, но потом требует 500 строк, чтобы поддерживать реальные правила продукта, это плохой обмен.
Простой способ выбрать
Большинство библиотек выглядят нормально, когда вы сортируете плоский список на ноутбуке. Но такое демо почти ничего не говорит. Вместо этого используйте один реальный экран из вашего приложения — тот, с которым люди будут работать каждый день.
Лучше всего работает маленький и конкретный тест. Сделайте один planner, один экран kanban-доски на React или один поток сортируемого списка. Включите туда то, что ломается первым: пустую колонку, переполненную колонку и один элемент с длинным заголовком.
На первый проход выберите только две операции. Например, перемещение карточки между колонками и сортировку карточек внутри одной колонки. Если вместо перемещения вам нужен режим копирования, подставьте его сразу. Эти две операции расскажут вам больше, чем любой фальшивый полноэкранный прототип.
Потом проверьте то, что команды часто пропускают. Попробуйте drag на телефоне, а не только мышью. Попробуйте перемещение с клавиатуры. Попробуйте drop в пустое состояние. После этого добавьте одно реальное правило из продукта: заблокированную колонку, карточку, которая может копироваться, но не перемещаться, или дорожку, которая принимает только определенные элементы.
Именно здесь nested drag and drop часто начинает ощущаться неудобно, а объем дополнительного кода быстро растет. Оставляйте библиотеку, которая требует меньше обходных решений. Обычно это означает меньше связок для состояния, меньше исправлений collision и меньше собственного кода вокруг touch-поведения.
Если один пакет выглядит умнее, но требует вдвое больше усилий, чтобы поддерживать обычные правила продукта, откажитесь от него. Скучный вариант часто побеждает, потому что ваша команда сможет менять его и через шесть месяцев.
Пример: планировщик команды со swimlanes
Представьте недельный планировщик с пятью вертикальными дорожками — по одной на каждый рабочий день. Каждая карточка — это задача. Людям нужно перетаскивать карточки вверх и вниз внутри дня, переносить их в другой день и нажимать на карточку, чтобы открыть детали, не цепляя drag-handle.
Теперь добавим еще один слой: внутри каждой карточки есть короткий чеклист или набор подзадач. Этот вложенный участок меняет всю задачу. Переставлять карточки между днями — это обычное дело. Переставлять элементы чеклиста внутри карточки, пока сама карточка по-прежнему может перемещаться между дорожками, — вот где многие демо sortable list перестают быть полезными.
Для такого планировщика компромиссы становятся очевидны. Легкий инструмент для сортировки приятен для плоских карточек, но начинает мешать, когда у карточек появляется собственный draggable-контент. dnd-kit хорошо подходит для board-структуры и дает контроль над sensors, collision rules и touch-поведением, но логику приходится писать самому. @hello-pangea/dnd ближе к готовой доске для дорожек и карточек, но nested drag and drop там все равно остается неудобным, а собственные правила быстро накапливаются. React DnD может справиться почти с любым взаимодействием в таком planner, но настройка тяжелее, и умственная нагрузка ощутима.
Такой экран также требует мелких правил, которые демо пропускают. Возможно, в пятницу после 17:00 редактирование только для чтения. Возможно, в колонке может быть не больше десяти задач. Возможно, на мобильном нажатие на карточку должно открывать детали, а drag должен запускаться только с маленького handle. Именно такие детали решают, будет ли библиотека приятной или утомительной.
Если planner останется плоским, простого sortable-пакета может хватить. Если nested drag and drop уже есть в дорожной карте, dnd-kit часто безопаснее всего брать первым. Он требует больше настройки в начале, но обычно причиняет меньше боли, когда продуктовые запросы начинают накапливаться.
Ошибки, которые съедают время
Многие команды выбирают библиотеку так же, как выбирают UI-kit: по звездам на GitHub, красивым демо или статье в блоге трехлетней давности. Обычно это заканчивается плохо. Код drag and drop ломается мелко и раздражающе, и такие проблемы почти никогда не видны на скриншотах.
Первая дорогая ошибка — не тестировать телефон и планшет, пока доска уже работает на десктопе. Drag мышью может ощущаться отлично, а touch — быть липким, с задержкой или вообще не срабатывать рядом со скроллом страницы. Если ваши пользователи будут переставлять задачи с телефона, проверяйте это в первый же день, а не после половины проекта.
Еще одна ловушка — начинать с nested drag and drop раньше, чем простые перемещения станут надежными. Команды одновременно строят swimlanes, карточки, подкарточки, сворачиваемые группы и собственные правила drop. А потом уже никто не понимает, ошибка это библиотеки, макета или собственной логики состояния.
Virtualization создает похожую боль. Слишком рано оптимизировать кажется умной идеей, особенно для длинных списков, но виртуализированные строки могут менять размеры и ломать drag-поведение в неочевидных местах. Сначала добейтесь стабильного перетаскивания. Потом добавляйте virtualization и тестируйте снова.
Самая большая трата времени — пытаться заставить пакет вести себя как другой пакет. Если вы уже заменили sensors, collision rules, previews, обработку клавиатуры и половину потока событий, значит библиотека вам мешает. Многие пакеты хороши внутри своих границ. За пределами этих границ они быстро становятся дорогими.
Простое правило помогает: как только список обходных решений начинает расти каждую неделю, переставайте чинить. Ранний переход почти всегда дешевле, чем тащить хрупкую настройку через весь проект.
Короткие проверки перед тем, как решиться
Библиотека может выглядеть плавно в демо и все равно мешать в настоящем приложении. Перед тем как решиться, соберите грубый тестовый экран и сначала проверьте самые неприятные случаи. Десять неидеальных минут сейчас могут сэкономить дни переписывания потом.
Если можете, используйте реальное устройство. Телефон, планшет, ноутбук с тачпадом и настольная мышь ведут себя по-разному. Многие React drag and drop-библиотеки нормально работают с мышью, а потом становятся неловкими, когда большой палец должен и скроллить, и перетаскивать в одном и том же месте.
- Перетащите одну и ту же карточку на телефоне, планшете и компьютере. Смотрите на рывки, блокировку скролла страницы и слишком маленькие handle.
- Переместите элементы в пустую колонку и в список, где карточки стоят почти вплотную друг к другу. Плохое определение drop там проявляется быстро.
- Начните drag, а затем отмените его через Escape, броском вне цели и переключением фокуса. Приложение каждый раз должно возвращаться в чистое состояние.
- Откройте меню внутри карточки, напишите что-нибудь в поле ввода, выделите текст, а потом перетащите. Обычные элементы управления должны оставаться обычными.
- Прочитайте свой собственный код drag на следующий день. Если для одного небольшого поведения нужны дополнительные refs, таймеры и патчи, эта боль будет только расти.
Этот тест говорит больше, чем любая таблица функций. Пакет обычно безопасен тогда, когда скучные действия остаются скучными: пользователь перетаскивает, нажимает, вводит, отменяет и возвращается назад без сюрпризов.
Если ваша доска проваливает хотя бы одну из этих проверок, отнеситесь к этому серьезно. Система drag стоит в центре всего экрана. Когда она ведет себя нестабильно, каждая маленькая задача начинает ощущаться сложнее, чем должна.
Что делать дальше
Начните с одного реального экрана, а не со списка пожеланий по функциям. Соберите небольшой прототип той доски, которая действительно нужна вашей команде, и выделите на это один день. Planner с двумя swimlanes, несколькими карточками и перетаскиванием между колонками расскажет вам больше, чем часы сравнения пакетов.
Перед тестированием запишите правила, которые нельзя нарушать. Формулируйте их просто и конкретно. Если карточка должна оставаться внутри своей дорожки, так и напишите. Если мобильным пользователям нужно перетаскивать элемент одним пальцем, тоже запишите это. Так вы перестанете оценивать библиотеки по демо и начнете оценивать их по своему продукту.
Достаточно простого чеклиста: какие действия пользователи делают каждый день, что должно происходить на touch-устройствах, как должны вести себя пустые колонки или группы и какие ограничения в макете строгие, а какие гибкие.
Оставьте место для polish. Touch drag and drop часто требует дополнительной работы, даже если библиотека заявляет поддержку. Пустые состояния тоже требуют внимания. Пустая колонка без понятной зоны drop быстро кажется сломанной, и пользователи замечают это раньше, чем замечают ваш код.
Если вашей доске уже нужны nested drag and drop, собственные collision rules или необычная логика planner, честно оцените стоимость. Именно здесь многие команды теряют неделю, а потом выбрасывают первый пакет. Короткий архитектурный разбор может оказаться дешевле переписывания.
Если перед принятием решения вам нужен второй взгляд, Oleg Sotnikov на oleg.is помогает стартапам и небольшим командам с архитектурой продукта, инфраструктурой и Fractional CTO. Для проектов со сложным поведением интерфейса и большим количеством будущих крайних случаев короткая консультация может помочь заметить проблемы поддержки заранее.
Часто задаваемые вопросы
Что выбрать для простого sortable list в React?
Если вам нужно только упорядочивать элементы в одном списке, начните с самого простого инструмента, который хорошо работает на ваших устройствах. Для многих React-приложений здесь хорошо подходит dnd-kit, но подойдет и любой небольшой вариант для сортировки, если он стабильно работает на телефоне и на компьютере.
Какая библиотека лучше всего подходит для kanban-доски?
Для доски с колонками и карточками часто безопаснее всего начать с dnd-kit, потому что он лучше справляется с мышью, touch и клавиатурой, чем многие старые решения. Если ваша доска близка к классической структуре «список в списке», @hello-pangea/dnd тоже может сначала казаться удобнее.
Когда React DnD подходит лучше, чем dnd-kit?
Выбирайте React DnD, если на экране есть необычные drop-зоны, много типов элементов или правила, которые меняются в зависимости от роли или контекста. Он дает больше контроля, но за это приходится платить более сложной настройкой и большим количеством кода.
Достаточно ли нативного HTML drag and drop?
Обычно — нет. Нативный drag and drop может подойти для внутреннего инструмента только для десктопа, но поддержка touch, превью и обратная связь при сортировке часто быстро требуют дополнительной работы.
Почему поддержка touch так сильно влияет на выбор?
Мышь скрывает много проблем. На телефоне пользователю приходится скроллить, нажимать и перетаскивать в одном и том же пространстве, поэтому плохой тайминг или отсутствие удобных handle сразу делают всю доску «сломанной».
Как понять, что пустые колонки могут стать проблемой?
Сделайте тестовую колонку без карточек и попробуйте перетащить в нее элемент в первый же день. Если библиотеке нужны фейковые spacer-элементы или странные обходные пути только ради того, чтобы принять одну карточку, дальше проблем обычно станет больше.
Вложенные макеты плохо подходят для большинства библиотек drag and drop?
Могут, особенно если карточки сами содержат элементы, которые тоже можно перетаскивать. Родительские и дочерние зоны drop часто мешают друг другу, поэтому перед выбором пакета стоит проверить один реальный экран с вложенной структурой.
Стоит ли сразу добавлять virtualization для длинных списков?
Нет, не в начале. Сначала сделайте перетаскивание стабильным, а потом добавляйте virtualization, потому что виртуальные строки могут менять размеры и создавать трудные для поиска ошибки.
Как быстрее всего сравнить библиотеки?
Используйте один реальный экран из продукта и проверьте только несколько повседневных действий. Если один пакет требует меньше обходных решений для touch, пустых состояний и заблокированных drop, оставляйте его, даже если демо выглядит менее эффектно.
Когда нужен архитектурный ревью перед разработкой drag and drop?
Приглашайте внешнюю помощь, когда доска уже требует вложенных перемещений, собственных правил и особого поведения на touch одновременно. Короткое архитектурное ревью или консультация Fractional CTO может сэкономить вам недели, потраченные на исправление не того инструмента.