# Trade-offs

> The costs of the native-first architecture: browser focus, a verbose protocol, author ids, complex widgets, build tooling, browser-defined semantics, and the preview status.

Page: https://svelte-lean.vercel.app/docs/trade-offs · Markdown: https://svelte-lean.vercel.app/docs/trade-offs.md · Index: https://svelte-lean.vercel.app/llms.txt

The costs the native-first architecture carries today, with what mitigates each and what does not.

## Costs

| Cost | Mitigation | Not mitigated |
| --- | --- | --- |
| Native paths need current browsers: invoker commands shipped in 2025, CSS anchor positioning is not yet Baseline. | Each contract names the feature and its fallback (two calls for a dialog, a centered popover); [Browser support](https://svelte-lean.vercel.app/docs/browser-support.md) collects them. | No polyfill and no compatibility module, by design. |
| The protocol is verbose: every trigger carries role, id, `aria-controls`, `aria-selected` and `tabindex`. | Development validation names a missing panel, a duplicate value or a broken relationship in the console. | The typing is yours; no snippet or wrapper component is provided. |
| Author ids are required, so a component rendered twice needs an id prop. | Server output is correct before hydration and identical on both sides. | Generated deterministic ids are not built. |
| Complex widgets still need JavaScript: the owned select registration is 5022 B brotli, tabs 1839 B brotli, kernel included. | The cost stays on pages that use the widget, and the controller exists only for roots that were used ([runtime profile](https://svelte-lean.vercel.app/primitives/select.md#runtime-profile)). | Bytes and main-thread work like any implementation. |
| Discovery is a Vite plugin with a lexical scan: no runtime markup, no `node_modules`, no dynamic identifiers, no non-Vite builds. | The manual import ships the same bytes, has its own fixture, and the manifest shows what the scan found. | One more build plugin; its order matters when a preprocessor rewrites markup. |
| Native behavior has browser semantics: Escape closes a dialog, a popover light-dismisses, `::details-content` animation depends on support. | Contracts state which parts are the browser's before the work starts. | A different interaction means leaving the native path. |

## A preview

- 23 behaviors carry the runtime side; 27 primitives ship none ([catalog](https://svelte-lean.vercel.app/primitives.md)).
- Submenus, mnemonics and virtualized lists are not implemented.
- The packages are at `0.17.4`, before 1.0; the deprecation policy has not been exercised.
- The tabs registration is above the initial size target of ADR 0003 ([targets and measurements](https://svelte-lean.vercel.app/docs/architecture/runtime-tiers.md#targets-and-measurements)).
- What each stage requires: release stages; where the project stands: docs/release.md.

## One browser in the tests

Browser tests run in Chromium only; no recorded Firefox or WebKit run and no screen-reader session exist. The claim registry marks these as not claimed and the [test matrix](https://svelte-lean.vercel.app/docs/architecture/accessibility.md#test-matrix) shows the gaps. Where another library fits better, the [comparison](https://svelte-lean.vercel.app/docs/why-not-bits-ui.md) pages say so.
