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/stylespnpm add @kernelui-lib/react @kernelui-lib/stylesyarn add @kernelui-lib/react @kernelui-lib/stylesbun add @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
| Built on | ||
|---|---|---|
| Accordion | <details> + <summary> | Data Display |
| Agent Activity | <ol> of steps | AI |
| Avatar | <img> | Primitives |
| Badge | <span> | Primitives |
| Breadcrumbs | <nav aria-label="breadcrumb"> + <ol> | Navigation |
| Button | <button> | Primitives |
| Callout | role="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
renderprop, notasChildmagic. 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><script type="module">
import "@kernelui-lib/elements";
</script>
<kernel-button variant="primary">Save changes</kernel-button>import { Button } from "@kernelui-lib/react";
// No "@kernelui-lib/react/styles.css" import anywhere —
// <Button> is still a real <button>, just unstyled.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;classNamestill targets the table and the newwrapperClassNametargets 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 newfilterLabel(filter-label) for the visible label, which falls back tofilterPlaceholderas before. Pagination's page list wraps instead of overflowing. - Surface-aware fills. New
--kernel-color-fill-subtle,--kernel-color-filland--kernel-color-fill-strongtokens 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'sedgeShadowis 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-insetand--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.TabsListalso takesshape="pill"(shape="pill"on<kernel-tabs-list>) for a fully rounded list whatever the theme. Slider gainsvariant="inset"(variant="inset"on<kernel-slider>): a full-height track filled with the accent colour, dragged by a slim bar, with optionalstartLabel/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-controllike 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-insetand 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 rendersdefaultOpenas theopenattribute, 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-event14.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.
On LLMs