# Compared with Bits UI

> A component model and a platform-first DOM protocol compared without claims about the other library; when to choose which, and how they coexist.

Page: https://svelte-lean.vercel.app/docs/why-not-bits-ui · Markdown: https://svelte-lean.vercel.app/docs/why-not-bits-ui.md · Index: https://svelte-lean.vercel.app/llms.txt

Bits UI offers accessible primitives through a component model, Svelte Lean a platform-first DOM protocol with selective behavior, and either can be the right answer.

## Two models

| Concern | Bits UI | Svelte Lean |
| --- | --- | --- |
| Unit of interaction | Imported components (root, trigger, content) | Markup on a protocol; nothing imported |
| State and handlers | Owned by each component instance | In the DOM; one shared listener per event type |
| Native elements | Managed in JavaScript, independent of native support | The browser owns dialog, popover, details, form controls |
| Roles, ids, relationships | Generated | Written in the markup by the author |

## Measured

The same UI in each library, production Vite builds, same Svelte version; library JavaScript excludes Svelte's runtime. Cases and script: benchmarks/compare.

| UI | Svelte Lean JS (brotli) | Bits UI JS (brotli) | Svelte Lean characters | Bits UI characters | Svelte Lean lines | Bits UI lines |
| --- | --- | --- | --- | --- | --- | --- |
| Dialog | 0 B | 12378 B | 330 | 340 | 18 | 16 |
| Menu | 1908 B | 27114 B | 414 | 376 | 22 | 13 |
| Tabs | 1488 B | 5437 B | 836 | 339 | 54 | 13 |

A thousand tabs mounted in headless Chrome, from before `mount()` to the second animation frame, and the heap after a forced garbage collection:

| Library | Mount, median | Range | Heap, median |
| --- | --- | --- | --- |
| Svelte Lean | 35.1 ms | 33.6 ms to 36.2 ms | 2.3 MB |
| Bits UI | 220.8 ms | 209.9 ms to 233.6 ms | 48.9 MB |

Bits UI 2.19.3, Svelte 5.57.1, Vite 7.3.6, chrome 153.0.8010.53, Apple M2, 2026-09-27. Nine fresh pages per mount case.

## What the numbers do not say

- The dialog costs Svelte Lean nothing because the browser ships it; Bits UI adds configurable focus management and scroll lock and works without invoker commands.
- The markup is not shorter: a dialog is about equal, a menu a little longer, tabs much longer. Characters exclude whitespace; lines are counted after Prettier at 64 columns.
- One machine, one browser, client-side mounting; no server rendering, hydration or accessibility measured.

## Choosing

- **Bits UI** when your team wants a typed component for every interaction, needs a widget beyond the 23 behaviors and the native primitives Svelte Lean ships, or wants one library to own the widget regardless of native browser support.
- **Svelte Lean** when native primitives should work before hydration and without JavaScript, the markup should be the single representation, the listener and bundle invariants matter, and you accept writing protocol attributes and ids. Its costs are on [Trade-offs](https://svelte-lean.vercel.app/docs/trade-offs.md).

## Coexistence

Both can share an application: Svelte Lean behaviors respond only to roots marked `data-slean`, and native primitives have no provider. A single widget is either a component or protocol markup.
