GitHubnpm

Accent theme

Base radius

GitHubnpm

Accent theme

Base radius

Colour scheme

Docs menu

Guides


Primitives
Forms
Layout
Feedback
Overlays
Navigation
Data Display
AI

Migration from shadcn/Radix

Kernel covers most of the same UI surface as shadcn/ui, but the APIs are not drop-in replacements. Many components are structurallydifferent because Kernel wraps real native elements (<dialog>,<select>, <details>) instead of Radix's compound component trees.

Start with kernel init and kernel doctor — see the CLI guide. Then migrate screen by screen rather than attempting a whole-repo rewrite.

What changes everywhere

  • asChildrender — polymorphic composition uses a render prop, not Radix Slot.
  • Required labels — form fields need a labelprop; use hideLabel when the label should be visually hidden.
  • No copied source — you install packages and import components; there is no components/ui/ folder to own.
  • CSS, not a theme provider — theming is CSS custom properties from @kernelui-lib/styles, not a React context.
<Button render={<a href="/docs">Docs</a>}>
  Read the docs
</Button>

Component mapping

The table below is generated from the shared registry. Runkernel docs <shadcn-name> for details on any row.

Kernelshadcn aliasReact export
Accordionaccordion, collapsibleAccordion
AvataravatarAvatar
BadgebadgeBadge
BreadcrumbsbreadcrumbBreadcrumbs
ButtonbuttonButton
CalloutalertCallout
CardcardCard
CarouselcarouselCarousel
CheckboxcheckboxCheckbox
Comboboxcombobox, commandCombobox
Command PalettecommandCommandPalette
Context Menucontext-menuContextMenu
Data Tabledata-table, tableDataTable
Date Pickercalendar, date-pickerDatePicker
Date Range Pickerdate-range-pickerDateRangePicker
Dialogdialog, alert-dialogDialog
Dropdown Menudropdown-menu, menubarDropdownMenu
Hover Cardhover-cardHoverCard
Input OTPinput-otpInputOTP
LabellabelLabel
Navigation Menunavigation-menuNavigationMenu
PaginationpaginationPagination
PopoverpopoverPopover
ProgressprogressProgress
Radio Groupradio-groupRadioGroup
ResizableresizableResizable
Scroll Areascroll-areaScrollArea
SelectselectSelect
SeparatorseparatorSeparator
Sheetsheet, drawerSheet
SidebarsidebarSidebar
SkeletonskeletonSkeleton
SlidersliderSlider
SwitchswitchSwitch
TabletableTable
TabstabsTabs
Text FieldinputTextField
TextareatextareaTextarea
Toasttoast, sonnerToastViewport
Toggletoggle, toggle-groupToggle
TooltiptooltipTooltip

Structural differences to plan for

Accordion

  • Radix Accordion uses controlled value/onValueChange on the root; Kernel AccordionItem uses title + defaultOpen per item.
  • No Radix-style AccordionTrigger/AccordionContent composition — pass title and children to AccordionItem.

Button

  • shadcn asChild maps to Kernel's render prop: <Button render={<a href="..." />}>.

Checkbox

  • onCheckedChange naming matches Radix; value API uses checked/defaultChecked/onCheckedChange.

Combobox

  • Custom Radix/shadcn Select with search/filter usually maps here, not native Select.
  • Options are passed as an options prop array, not SelectItem children.

Data Table

  • TanStack Table column definitions differ; Kernel DataTable takes a columns prop with a simpler API.

Dialog

  • Kernel Dialog is a single component with title/description/children props — not Dialog.Root/Trigger/Portal/Content.
  • shadcn Alert Dialog is this component with closeOnBackdropClick={false}. shadcn Sheet is Kernel Sheet, which adds drag-to-dismiss on top of this.

Dropdown Menu

  • Use render prop instead of asChild on the trigger: <DropdownMenu render={<Button />}>.

Popover

  • Use render prop on the trigger instead of asChild.

Select

  • Kernel Select wraps a native <select> — the OS renders the picker.
  • Custom portal/listbox Select from Radix usually maps to Combobox instead.
  • Use SelectOption (or real <option> in elements) instead of SelectItem.

Sheet

  • Replaces Vaul: Drawer.Root/Trigger/Portal/Overlay/Content/Handle collapse into one <Sheet> with open/onOpenChange, since a real <dialog> needs no portal and draws its own ::backdrop.
  • Vaul's snapPoints becomes snapPoints (viewport percentages) and activeSnapPoint becomes snap/defaultSnap/onSnapChange; snapping works on every side, as a percentage of the axis the sheet grows along.
  • direction becomes side; dismissible and handleOnly keep their names; closeThreshold keeps Vaul's 0.25, but velocityThreshold is 0.5 because release speed is measured over a window rather than the whole gesture.

Switch

  • onCheckedChange naming matches Radix.

Tabs

  • value/onValueChange API matches Radix; subcomponent names differ (Tab vs TabsTrigger).

Text Field

  • label is required — use hideLabel for visually hidden labels.
  • shadcn Input without a label needs a TextField with label + hideLabel.

Textarea

  • label is required — same form-field scaffold as TextField.

Toast

  • Mount <ToastViewport /> once, then call toast() from anywhere — similar to Sonner.

Tooltip

  • Use render prop on the trigger instead of asChild.

Common patterns

Input → TextField

shadcn's unlabeled Input becomes a TextField with a required label:

<TextField
  label="Email"
  hideLabel
  type="email"
  placeholder="you@example.com"
/>

Dialog / Sheet / Alert Dialog

All collapse into one Dialog component withtitle, description, and childrenprops — not a Root/Trigger/Portal/Content tree.

<Dialog
  open={open}
  onOpenChange={setOpen}
  title="Delete project"
  description="This cannot be undone."
>
  <p>Project files will be permanently removed.</p>
</Dialog>

Select vs Combobox

  • Select — native<select>; the OS renders the picker. Use when a platform-native picker is acceptable.
  • Combobox — custom filterable listbox. Use when migrating a styled Radix Select with search or custom item rendering.

Incremental adoption

  1. Run kernel init in a branch.
  2. Pick one screen or feature to migrate.
  3. Start with mechanical swaps: Button, Badge, Separator, Checkbox, Switch.
  4. Tackle structural components (Dialog, Select, Accordion) with the caveats above.
  5. Use headless mode (tokens only) on pages you have not migrated yet.