GitHubnpm

Accent theme

Base radius

GitHubnpm

Accent theme

Base radius

Colour scheme

The kernel of the web, componentised.

A component library built on real semantic HTML instead of div soup.

npm install @kernelui-lib/react @kernelui-lib/styles
  • 60 components
  • 0 runtime deps
  • MIT licensed
  • React and Web Components

Comparison

What a real element buys you

Same button, same look. One gets focus, keyboard activation, and disabled state from the browser for free. The other has to catch up by hand, and still won't get form submission or :focus-visible right without more code.

Kernel

<button
  type="button"
  onClick={save}
>
  Save changes
</button>

Div soup

<div
  role="button"
  tabIndex={0}
  aria-disabled="false"
  onClick={save}
  onKeyDown={(e) => {
    if (e.key === "Enter" || e.key === " ") {
      e.preventDefault();
      save(e);
    }
  }}
>
  Save changes
</div>

The library

Every component, and the element doing the work

The full catalogue, in Kernel's own DataTable: filter it, sort it, page through it, and open any component's docs. The middle column is the whole idea — each one names the native element it's built on.

60 results

60 components and the element each one is built on
Built on
Accordion<details> + <summary>Data Display
Agent Activity<ol> of stepsAI
Avatar<img>Primitives
Badge<span>Primitives
Breadcrumbs<nav aria-label="breadcrumb"> + <ol>Navigation
Button<button>Primitives
Calloutrole="alert" / role="status"Feedback
Card<article> / <div>Layout

Principles

How it's built

Four decisions that shape every component, not just the ones on this page.

Composition
An explicit render prop, not asChild magic. What actually renders is always visible at the call site.
State
Real pseudo-classes — :checked, :disabled,:user-invalid — wherever the browser already gives you one. data-* everywhere else.
Distribution
A versioned, tree-shakeable npm package, not a copy-paste registry. Import what you use.
Naming
The actual kernel of the web: the elements and behaviour browsers already ship.

Platforms

Everywhere you already build

Three ways in. @kernelui-lib/react is the flagship. @kernelui-lib/elements is the same design system as native Custom Elements — Vue, Svelte, Astro, or plain HTML, no wrapper required. Or skip the stylesheet on either one and get real, fully-functional semantic elements with none of Kernel's own look — just the bones, themed however you want.

import { Button } from "@kernelui-lib/react";

<Button variant="primary">Save changes</Button>

More on platforms & headless usage →

Theming

One value, one cascade

Every colour, corner and gap is a CSS custom property. These controls are Kernel components changing the real site — not a preview pane — and the code beside them is the theme you'd paste into your own app.

Opens beside the page, so you can scroll around and watch it change.

Changelog

Recently shipped

Straight from the published package's changelog. This list is an Accordion on <details>, so it works with no JavaScript at all.

@kernelui-lib/react 1.6.1Patch
  • Tabs re-measures its selection indicator whenever the tab list changes size. A tab list first rendered inside a hidden container (a closed dialog, popover or <details>) used to measure every tab as 0px wide and show a zero-width sliver with no selected highlight until the selection changed; it now snaps into place when the container opens, and also follows font loading or the container resizing.
@kernelui-lib/react 1.6.0Minor
  • Tables are mobile-friendly. Table (and <kernel-table>) now renders its <table> inside a horizontal scroll container, so a wide table scrolls in place instead of widening the page on a phone; className still targets the table and the new wrapperClassName targets the container. An edge fade and inset shadow show which side still has content to scroll to, driven by a CSS scroll-driven animation. DataTable gets the same scroll container, its pagination wraps (centred) when the page links don't fit on one line, and the filter field gains a real placeholder: filterPlaceholder (filter-placeholder) now sets it, with a new filterLabel (filter-label) for the visible label, which falls back to filterPlaceholder as before. Pagination's page list wraps instead of overflowing.
  • Surface-aware fills. New --kernel-color-fill-subtle, --kernel-color-fill and --kernel-color-fill-strong tokens back every well, track and hover background (Tabs, inset and default Slider, Progress, Skeleton, Toggle, Pagination, date pickers, Table row hover, Avatar, Badge, Carousel, Toast). Card re-sets them one grey step up and raised containers (Dialog, Sheet, Popover, HoverCard, DropdownMenu, ContextMenu, NavigationMenu, Toast, CommandPalette, Combobox and Select popups) two, so a Tabs track or Slider keeps its contrast instead of disappearing into a raised surface of the same grey. ScrollArea's edgeShadow is now driven by a CSS scroll-driven animation (same 48px ramp); its scroll listener only runs as a fallback in browsers without scroll timelines.
  • Updated dependencies [9c181a0] - @kernelui-lib/styles@1.4.0
@kernelui-lib/react 1.5.0Minor
  • Add shared control tokens: --kernel-control-height-sm/md/lg, --kernel-control-inset and --kernel-radius-control-inner (control radius minus inset, so nested pieces stay concentric at every theme rounding). Button, Toggle, TextField, NumberField, Select, Combobox, ColorPicker, Pagination, Carousel and CommandPalette now read the height tokens instead of literal values. Tabs now follows --kernel-radius-control: the list uses the control radius and height, and tabs and the indicator use --kernel-radius-control-inner, so a tab list is square at Sharp and a pill at Round, matching the buttons beside it. TabsList also takes shape="pill" (shape="pill" on <kernel-tabs-list>) for a fully rounded list whatever the theme. Slider gains variant="inset" (variant="inset" on <kernel-slider>): a full-height track filled with the accent colour, dragged by a slim bar, with optional startLabel/endLabel (start-label/end-label) captions that change colour where the fill crosses them. When the drag bar would land on a caption, the bar steps aside at rest and the caption steps aside while the slider is hovered, dragged or keyboard-focused. The default slider's fill now lines up with the thumb's centre, its focus ring shows again in Chromium and Safari, and server-rendered sliders show the right fill before hydration. Shape drift fixes: Pagination items use --kernel-radius-control like every other control; Combobox and CommandPalette options are now concentric with the surface around them (as Select's options already were); Switch derives its thumb gap from --kernel-control-inset and is square when the theme's control radius is 0 (still a pill in any rounded theme).
  • DataTable's filter and sort fallback now read the text inside rendered elements, so a cell that wraps its value in a link, <code> or Badge is still searchable and sortable (matching <kernel-data-table>). AccordionItem renders defaultOpen as the open attribute, so a default-open item is open in server-rendered HTML and without JavaScript instead of opening after hydration.
  • Update development dependencies: Vite 8.3.5, @testing-library/user-event 14.6.8 and Node.js 26.6.5 types.
  • Update the package build dependencies to Vite 8.3 and Node.js 26.6 types.
  • Update React and React DOM development dependencies to 19.3.1, with matching type definitions.
  • Updated dependencies [6b93625] - @kernelui-lib/styles@1.3.0
@kernelui-lib/react 1.4.4Patch
  • Enhance single selects with a native, token-styled picker when appearance: base-select and ::picker(select) are supported. Preserve the existing control styling, chevron, and platform picker fallback, and leave multiple selects and listboxes unchanged.

Get started

Built on the parts of the web that already work.

Kernel is MIT-licensed and developed on GitHub. Contributions to docs, accessibility, and component parity are welcome.60 components are ready today. The full set is live.