12k
All articles

shadcn/ui перешёл с Radix на Base UI

shadcn/ui перевел новые проекты с Radix на Base UI. Узнайте, что изменилось, кому не нужна миграция и какова ее реальная цена.

OpenReplay Team
OpenReplay Team
shadcn/ui перешёл с Radix на Base UI

Если ваше приложение на shadcn/ui работает на Radix, мигрировать не нужно. Base UI теперь используется по умолчанию для новых проектов, но Radix остаётся полностью поддерживаемым: обновления выходят для обеих библиотек, а команда shadcn по-прежнему использует Radix в своих продакшн-приложениях.

Изменение вступило в силу 3 июля 2026 года. Значительная часть последующих публикаций подразумевала, что грядёт переписывание кода, — но в changelog говорится не об этом.

Дальнейшие действия определяются двумя вопросами: обязаны ли вы что-то предпринимать и во сколько обойдётся миграция, если вы на неё решитесь. Стоимость делится на изменения, которые ловит компилятор, и те, которые он не ловит, — и именно во второй категории кроется риск.

Ключевые выводы

  • Base UI — вариант по умолчанию для новых проектов shadcn/ui; Radix не объявлен устаревшим, а флаг -b radix сохраняет Radix при новой инициализации.
  • Существующим приложениям на Radix не требуется никаких изменений: обновления выходят для обеих библиотек, и команда shadcn по-прежнему использует Radix в продакшене.
  • Значение по умолчанию изменилось, потому что Base UI достиг стабильной версии 1.6.0 с более чем шестью миллионами загрузок в неделю, а пользователи shadcn/create выбирали его вместо Radix в соотношении два к одному.
  • Миграция делится на изменения, ломающие сборку (asChildrender, Positioner/Popup, nullable-значения Select), и молчаливые изменения поведения (ручная активация вкладок, меню, остающиеся открытыми) — именно последние составляют реальную стоимость.
  • Если вы мигрируете, держите обе библиотеки установленными, переносите по одному компоненту на коммит и используйте официальный skill от shadcn, а не codemod.

Что изменилось 3 июля 2026 года

Новые проекты shadcn/ui теперь по умолчанию используют Base UI, и больше ничто в существующих проектах не изменилось. Изменились три вещи. Запуск npx shadcn init выбирает Base UI, если вы не укажете иное; shadcn/create ставит Base UI в начало списка; а документация по компонентам теперь открывается на вкладке Base UI, рядом с которой находится вкладка Radix. Сам Radix не объявлен устаревшим.

Чтобы оставить Radix в новом проекте, достаточно одного флага:

pnpm dlx shadcn init -b radix

Везде, где CI или скрипт скаффолдинга вызывает shadcn init без интерактивного запроса и рассчитывает получить Radix, добавьте этот флаг сейчас. Значение по умолчанию, на которое опираются такие скрипты, изменилось.

Нужно ли мигрировать на компоненты shadcn Base UI?

Нет. В changelog зафиксировано обязательство выпускать каждое обновление и каждый новый компонент для обеих библиотек, с единственным исключением — компоненты, которые есть в Base UI и не имеют аналога в Radix. Там же сказано, что собственный продакшн-код команды по-прежнему работает на Radix и переносить его не планируется. У стабильного приложения на Radix нет ни навязанных сроков, ни окна устаревания, ни риска остаться без поддержки. Остальная часть статьи — для команд, которые решили перейти, а не для тех, кто обязан это сделать.

Почему изменилось значение по умолчанию?

В changelog приводятся четыре причины. Библиотека достигла стабильной версии 1.6.0 и превысила отметку в шесть миллионов загрузок в неделю. Её мейнтейнеры продолжают добавлять полезные примитивы. Команда shadcn уже стандартизировала её для всех новых разработок. А среди тех, кто создаёт проекты через shadcn/create, Base UI выигрывал примерно два выбора на каждый, приходившийся на Radix.

Эти цифры приведены в changelog. С тех пор Base UI продолжает развиваться: версия 1.8.0 вышла 4 сентября 2026 года. В changelog также отмечается, что Base UI создан теми же людьми, которые разработали Radix. Устанавливать нужно пакет @base-ui/react; у старого имени @base-ui-components/react в npm стоит пометка об устаревании с перенаправлением на новый пакет.

Что на самом деле меняет миграция

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

RadixBase UI
asChild у триггеровпроп render
Portal > ContentPortal > Positioner > Popup
OverlayBackdrop
варианты data-[state=open]:варианты data-open:
onOpenChange(open) + event.preventDefault()onOpenChange(open, details) + details.cancel()

Один нюанс: разделение на Positioner/Popup применяется к привязанным всплывающим элементам, таким как Menu, Select, Popover и Tooltip. У Dialog нет Positioner — там используются Dialog.Backdrop и Dialog.Popup.

Изменение колбэка выглядит так:

// Radix: block closing via the event
onEscapeKeyDown={(event) => event.preventDefault()}

// Base UI: one callback, with a reason and a cancel()
onOpenChange={(open, details) => {
  if (details.reason === "escape-key") {
    details.cancel()
    return
  }
  setOpen(open)
}}

Меняются и типы значений. Управляемый Select теперь возвращает Value | null, а не строку, что делает это самой частой поломкой сборки:

const [fruit, setFruit] = useState<string | null>(null)

Значения Accordion и Toggle Group всегда представляют собой массивы, даже в режиме одиночного выбора, поэтому value="a" превращается в value={["a"]}.

Изменения, которые компилируются, но ведут себя иначе

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

  • Вкладки по умолчанию активируются вручную. Стрелки перемещают фокус между триггерами, не переключая видимую панель, если только вы не установите activateOnFocus на Tabs.List — по умолчанию там false. В Radix по умолчанию использовалась автоматическая активация.
  • Пункты меню типа checkbox и radio оставляют меню открытым. У Menu.CheckboxItem и Menu.RadioItem closeOnClick по умолчанию равен false — противоположность поведению Radix, где меню закрывалось при выборе. У обычного Menu.Item по-прежнему true, так что поведение различается в зависимости от типа пункта.
  • NavigationMenu открывается быстрее при наведении. В Base UI delay по умолчанию равен 50 мс; в Radix delayDuration по умолчанию — 200 мс. Меню, мимо которых пользователи раньше просто проводили курсором, теперь будут открываться.

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

Кому стоит переходить на Base UI, а кому нет?

Мигрируйте, если вам нужны Combobox, Autocomplete или Number Field, которых в Radix никогда не было, либо если вы хотите оставаться в синхронизации с новыми компонентами реестра по мере их выхода. Оставайтесь на Radix, если ваше приложение стабильно и ничего из перечисленного к вам не относится: обязательства по поддержке зафиксированы явно, а работающее продакшн-приложение ничего не выигрывает от замены примитивов.

Не принимайте решение на основе слухов о пробелах в наборе компонентов. Base UI поставляет Context Menu, Toast и примитив hover-card под названием Preview Card, и документация shadcn по Base UI охватывает все три.

Как мигрировать, если вы всё же решились

Используйте официальный skill, а не codemod, и двигайтесь постепенно. Логика здесь безупречна. Codemod знает только «заводскую» версию файла, поэтому справляется с компонентами, которые вы не трогали, и спотыкается на тех, что вы изменяли. Skill читает то, что у вас есть на самом деле, переносит ваши правки и сообщает о различиях в поведении, вместо того чтобы молча их переписывать.

pnpm dlx skills add shadcn/ui

Затем попросите своего кодового агента мигрировать один компонент, например migrate accordion to base-ui. Обе библиотеки можно держать установленными одновременно, поэтому сборка остаётся «зелёной» между шагами. Каждый запуск проверяет типы того, что было сгенерировано, записывает заметку по этому компоненту в папку .migration/ и оформляет результат отдельным коммитом в ветке, которую можно спокойно удалить. Начинайте с листовых компонентов вроде button и label, прежде чем браться за компоненты, которые их импортируют, и перед мерджем читайте раздел с изменениями поведения в каждом отчёте.

Одно предупреждение: некоторые руководства предлагают переключить components.json на Base UI и заново добавить все компоненты с флагом --overwrite. Это уничтожит все локальные правки, внесённые вами в эти файлы, — именно тот сбой, ради предотвращения которого и существует skill.

Что это значит для вас

Значение по умолчанию изменилось, ваши обязательства — нет. Существующие приложения на Radix продолжают работать, новые проекты получают Base UI, если не передать -b radix, а миграция — это опциональный проект, видимая стоимость которого сводится к переименованиям, а скрытая — к изменениям поведения. Если вы всё же мигрируете, заложите время QA на молчаливые отличия, потому что именно там компилятор перестаёт помогать. Начните с самостоятельного прочтения записи в changelog, а затем решите, стоит ли Combobox или синхронизация с реестром отдельной ветки.

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

Готов ли Base UI к продакшену по сравнению с Radix?

Да. Base UI выпустил стабильную версию 1.0.0 в декабре 2025 года под пакетом '@base-ui/react' и с тех пор стабильно выпускает релизы, достигнув 1.8.0 к 4 сентября 2026 года. Библиотека создана авторами Radix, Floating UI и Material UI, и её команда заявляет, что намеренно сделала API похожим на Radix, чтобы переход между ними требовал меньше усилий. Команда shadcn также использует Base UI во всех новых проектах.

Все ли пропсы value в Base UI являются массивами?

Нет. У Accordion 'value' всегда массив, а у Toggle Group 'value' всегда массив строк, даже в режиме одиночного выбора, но у Tabs 'value' остаётся одиночным значением со значением по умолчанию 0, а Select типизирован как одиночное значение, массив или null. Оборачивайте значения Accordion и Toggle Group в массивы, типизируйте состояние управляемого Select как nullable и оставьте Tabs без изменений.

Влияет ли миграция на Base UI на компоненты shadcn, которые никогда не использовали Radix?

Нет. Command построен на cmdk, Sonner — самостоятельная библиотека тостов, Calendar использует react-day-picker, Input OTP использует input-otp, а Charts построены на recharts. Ни один из них не зависит от примитивов Radix, поэтому миграция с Radix на Base UI их не затрагивает. Изменения нужны только компонентам, чьи примитивы пришли из Radix, — таким как Dialog, Menu, Select, Tabs и Popover.

Требует ли skill для миграции shadcn использования pnpm?

Нет. В changelog описана установка skill для pnpm, npm, yarn и bun, поэтому 'npx skills add shadcn/ui' — корректный npm-эквивалент команды для pnpm. После установки skill работает через вашего кодового агента, который мигрирует по одному компоненту за раз и выдаёт код с проверенными типами, отчёт по каждому компоненту в директории '.migration' и один коммит на компонент — независимо от менеджера пакетов.

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.