Introduction
Svelte Lean is a Svelte-first UI ecosystem built around the web platform. It uses native browser behavior wherever possible and adds small, build-discovered interaction runtimes only where necessary.
On this page
What Svelte Lean is
Two products and the infrastructure they share. Svelte Lean Primitives (@svelte-lean/primitives) covers the interaction patterns of an application: buttons, dialogs, popovers, disclosures,
form controls, tabs, menus, listboxes and comboboxes. Svelte Lean Table (@svelte-lean/table) is a data table that renders a native <table> and grows into a data grid through
separate entry points.
The starting question for every primitive is the same: what does the browser already know how to
do? A <dialog> opened by an invoker command owns its top layer, page inertness,
Escape and focus return, so the package owns nothing for it beyond styles, a contract and development
validation. Tabs have no platform interaction, so one small behavior is registered once per page and
driven by attributes in the markup.
The runtime therefore grows with the interaction, not with the number of components. A page that uses only native primitives ships 0 B of Svelte Lean behavior JavaScript in the production fixture that proves it; a page with tabs ships the tabs registration and the shared kernel, 1521 B brotli.
What it is not
- Not a Tailwind component collection: the packages carry no CSS framework dependency.
- Not a Radix port or a Headless UI clone: behavior is not modelled as a component instance with its own listeners and state.
- Not a Web Components library: the markup is plain HTML that Svelte renders and hydrates.
- Not a replacement for Svelte, and not a claim that Svelte's event model is slow. The advantage is the absence of unnecessary abstraction, not a faster framework.
- Not anti-JavaScript. A correct combobox needs meaningful behavior code; the goal is the minimum necessary runtime, not zero runtime at any cost.
Who it is for
Teams that write markup and want the page to work before hydration and with client JavaScript disabled where the platform allows it. Applications on Svelte 5 and SvelteKit that render on the server, because every relationship in the markup uses authored ids and no state is generated at hydration. Projects that want to own their CSS and depend only on a maintained behavior engine.
It is a poorer fit for teams that prefer a component API for every interaction, or that need a primitive the platform does not yet cover well in their browser target. The trade-offs and the comparison pages say so in detail.
Two products
| Product | Package | Description |
|---|---|---|
| Svelte Lean Primitives | @svelte-lean/primitives | Native-first primitives driven by a DOM protocol: 40 Tier 0 primitives with no runtime, 15 Tier 1 behaviors with one shared listener per event type and 5 Tier 2 behaviors with a lazy per-root controller. |
| Svelte Lean Table | @svelte-lean/table | A data table for Svelte 5 that renders a native <table>, keeps its state in one plain object and adds capabilities through separate entry points. |
The two products share code only where it is genuinely reusable, through @svelte-lean/core; the table is not built on the primitives' runtime and does not
register behaviors (ADR 0006).
How behavior is shipped
Mode A, native only. Plain platform markup: a <dialog>, a popover, a <details>, native inputs. No package is required. The data-slean attributes on these elements are hooks for the optional stylesheet and for
development validation; the browser owns the behavior.
Mode B, package-managed behavior. For tabs, menus, listboxes and comboboxes the
markup carries a static marker such as data-slean="tabs". @svelte-lean/vite discovers the marker at build time and injects the matching registration module, so the production
bundle contains the behaviors the markup uses and nothing else. A manual import '@svelte-lean/primitives/tabs/register' is the documented escape hatch and ships
the same modules.
Mode C, owned styles. The stylesheet of a primitive is a plain CSS file that
can be copied into the application and edited there; the behavior engine stays in the package so
an accessibility fix reaches every project through npm. The slean add command that would
automate the copy does not exist yet.
The three modes render the same behavior contract. The whole model, with the shipping invariants and how each one is tested, is on Distribution.
What exists today
Every package is at version 0.2.0: a preview, not published to npm. The
repository is at release stage 0 with most of stage 1 in place, as recorded in docs/release.md on 2026-09-27. This section lists what exists;
the release document lists what each stage requires, and nothing beyond it is promised.
| Package | Role | Documentation |
|---|---|---|
@svelte-lean/primitives | Contracts and types for all 60 primitives; 15 Tier 1 and 5 Tier 2 behaviors as side-effect register modules | /primitives |
@svelte-lean/table | <DataTable />, createTable(), optional modules | /table |
@svelte-lean/styles | Optional CSS: tokens, base, one file per primitive | /styling |
@svelte-lean/vite | Build-time behavior discovery, manifest, build report | /docs/architecture/build-time-discovery |
@svelte-lean/core | Behavior registry, shared event router, DOM and keyboard helpers, diagnostics | /docs/architecture/dom-protocol |
Primitives: 40 native (Tier 0) primitives with no runtime, button, dialog, popover, disclosure, checkbox, switch, radio-group, date-field, input, field, segmented, rating, slider, otp-field, file-field, color-field, autocomplete, alert-dialog, drawer, accordion, card, separator, avatar, badge, tag, kbd, carousel, alert, progress, meter, spinner, skeleton, breadcrumb, pagination, steps, button-group, scroll-area, descriptions, timeline, empty; 15 delegated behaviors (Tier 1), each measured including the shared kernel, tabs (1521 B brotli), menu (1932 B brotli), listbox (1838 B brotli), calendar (3925 B brotli), toggle (888 B brotli), toggle-group (1569 B brotli), toolbar (1494 B brotli), range-slider (1291 B brotli), number-field (1082 B brotli), tree (1919 B brotli), tooltip (1297 B brotli), context-menu (1409 B brotli), file-drop (1107 B brotli), hover-card (1353 B brotli), menubar (1457 B brotli); 5 lazy scoped controller (Tier 2), combobox (2564 B brotli), date-picker (4912 B brotli), select (3362 B brotli), toast (1396 B brotli), splitter (1683 B brotli), whose per-root controller is created on the first interaction and released when focus leaves. Submenus are documented in the menu contract as not implemented; a command palette, a popconfirm and a multi-select dropdown are documented compositions of these primitives.
Table: <DataTable /> with sorting, search, column filters, pagination,
selection, expansion, tree rows, pinning, resizing, visibility, inline editing and keyboard cell
navigation as props; grouping, pivot, clipboard, CSV export, server data sources and persisted
state as separate entry points; createTable() underneath. Virtual rows are not shipped.
Not yet, and therefore not claimed: Firefox and WebKit test runs, screen-reader smoke tests, a command-line tool. The claim registry lists every public claim with its evidence and status.
Where to start
- Installation: packages, the Vite plugin, the stylesheets.
- Primitives: every primitive with its tier and measured cost.
- Table: the data table and its specimens.
- Proof: the runtime of this site, read live.