sveltelean
Versionv0.2.0 GitHub

Current browser focus

The native paths benefit most from current browser capabilities. Invoker commands shipped in 2025 and CSS anchor positioning is not yet Baseline, so an application whose target includes older browsers takes the documented fallback for those two features: two calls in application code for a dialog, and a centered popover. The package does not polyfill either, by design. Mitigation: every contract names the feature, its status and the fallback, and Browser support collects them; feature detection in application code is straightforward. Not mitigated: there is no compatibility module yet.

The protocol is verbose

Some developers prefer a component API. A tabs root on the protocol is longer than a <Tabs> component call: every trigger carries its role, its id, its aria-controls, its initial aria-selected and tabindex, and every panel its aria-labelledby. Svelte Lean deliberately values that transparency: the markup is what the browser, the server, CSS and assistive technology see, and there is no second representation to keep in sync. Mitigation: development validation reports a missing panel, a duplicate value or a broken relationship in the browser console, naming the trigger value concerned. Not mitigated: the typing is yours, and no snippet or component wrapper is provided for it today.

Author ids are required

Every ARIA relationship uses ids you wrote. That is what makes server output correct before hydration and the same on both sides, and it is a cost: two tabs roots on one page need distinct ids, and a component rendered several times needs an id prop. Generated deterministic ids are a possible later addition; they are not built.

Complex widgets still need JavaScript

A combobox is not free. It needs a controller with per-instance state, an active-descendant strategy, IME handling and asynchronous data, and it costs bytes and main-thread work like any other implementation. The tier model does not remove that cost; it isolates it to the instances that are used and keeps it out of pages that do not use the widget. The combobox is that Tier 2 primitive: its register module measures 2564 B brotli including the shared kernel, against 1521 B brotli for tabs, and its controller exists only for the roots that were used (Runtime profile).

Build integration adds tooling

Automatic discovery is a Vite plugin. It scans .svelte files lexically, so it does not see markup produced at runtime or in node_modules, and a dynamic identifier needs a manual import. A build that is not Vite gets no discovery at all. Mitigation: the manual import is the same module and the same bytes, it is tested by its own fixture, and the manifest and build report show what the scan found. Not mitigated: the plugin is one more thing in the build, and the plugin order matters when a preprocessor rewrites markup.

Native behavior has browser semantics

A native dialog closes on Escape, a popover light-dismisses, a details element animates only where ::details-content is supported, and a radio group's arrow keys behave as the browser decides. That is usually the point, and sometimes a limit: an interaction the platform defines differently from your design cannot be changed from the package without leaving the native path. The contracts state which parts are the browser's, so the limit is known before the work starts.

A preview

The runtime side of the model is carried by 20 behaviors, from tabs and menus to the calendar, the tree, the toast and the splitter; the other 40 primitives ship no runtime (the catalog lists them all). Submenus, mnemonics and virtualized lists are not implemented. The packages are a preview at 0.1.0-next, not published, and the deprecation policy has not been exercised. The tabs registration is measured above the initial size target of ADR 0003, which Runtime tiers shows next to the enforced budget. Anyone choosing the packages today is choosing an architecture preview, and the release stages say what each stage still requires.

One browser in the tests

Browser tests run in Chromium only; no Firefox or WebKit run and no screen-reader session exists. Timings are recorded by the benchmark project but no run is committed, so they read "not measured" in public. The claim registry marks each of these as not claimed, and the test matrix shows the gaps as gaps.

What this page is not

It is not a comparison with another library. No comparative benchmark exists, and where another library's model fits an application better, the comparison pages say so.