# Let the browser do the work.

> Svelte Lean is a Svelte-first, browser-native UI ecosystem: semantic HTML first, zero runtime where the browser owns the behavior, small shared behaviors where it does not.

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

Native elements first.

Shared listeners, not copies.

Zero bytes where the browser can.

Accessible primitives and a data table for Svelte 5.

[Browse components](https://svelte-lean.vercel.app/primitives.md)   [Get started](https://svelte-lean.vercel.app/docs/installation.md)

## Real components. Try them.

Every tile is the shipped primitive with its stylesheet. Open the code: it is all you write.

Weights are production JavaScript, brotli, per primitive. Zero means the browser does the work. [All primitives](https://svelte-lean.vercel.app/primitives.md)

## A few lines. No components.

No component imports, no wrappers. The Vite plugin reads the attributes and adds only the behaviors a page uses.

`share.svelte`

```svelte
<script lang="ts">
	import '@svelte-lean/styles/button.css';
	import '@svelte-lean/styles/dialog.css';
	import '@svelte-lean/styles/hint.css';

	let { url }: { url: string } = $props();
</script>

<button data-slean="button" commandfor="share" command="show-modal">
	Share
</button>

<dialog id="share" data-slean="dialog" closedby="any" aria-labelledby="share-title">
	<header>
		<h2 id="share-title">Share this page</h2>
		<p><code>{url}</code></p>
	</header>
	<footer>
		<button data-slean="button" data-slean-copy={url}
			data-slean-hint="Copy link" data-slean-hint-copied="Copied">
			Copy link
		</button>
		<button data-slean="button" data-variant="text" commandfor="share"
			command="close">Done</button>
	</footer>
</dialog>
```

- **Lines**: 23
- **Imports**: 3 stylesheets
- **Components**: 0

- [Dialog](https://svelte-lean.vercel.app/primitives/dialog.md) command="show-modal" opens it 0 B
- [Button](https://svelte-lean.vercel.app/primitives/button.md) a stylesheet on a \<button\> 0 B
- [Copy](https://svelte-lean.vercel.app/primitives/copy.md) data-slean-copy, shared listener 1.3 kB
- [Tooltip](https://svelte-lean.vercel.app/primitives/hint.md) data-slean-hint, one bubble per page 2.7 kB

## A real screen, built from primitives.

### What ran

Svelte Lean JavaScript behind the last action

0 B no action yet

1. Dialog The browser 0 B
2. Popover The browser 0 B
3. Checkbox The browser 0 B
4. Accordion The browser 0 B
5. Tabs Shared listeners 1.8 kB
6. Menu Shared listeners 2.8 kB
7. Select Lazy controller 5 kB
8. DataTable Component 20.8 kB

Open a dialog, switch a tab or sort a column.

- **Actions**: 0
- **Zero-byte actions**: 0
- **Listeners on the document**: …

[Production builds, brotli: how these are measured](https://svelte-lean.vercel.app/proof.md)

## Fifty thousand rows. Still a table.

Every row is a real row in the document. Off-screen rows are skipped by the browser, and the rest mount between frames.

Rows  1,000 10,000 50,000

The table mounts when this section comes into view.

`members.svelte`

```svelte
<DataTable
	{data}
	{columns}
	getRowId={(row) => row.id}
	layout="grid"
	progressive
	pagination={false}
	searchable
	stickyHeader
	height="30rem"
/>
```

Timings are taken in your browser as you watch, not published results. [Grid layout and progressive mounting](https://svelte-lean.vercel.app/table/layout.md#grid-layout) [The table: grouping, editing, pivot, export](https://svelte-lean.vercel.app/table.md)

## Ten thousand tabs. No new listeners.

Behavior is registered once per page, not copied into every instance. Mount more tabs and read the document again.

- **Tabs roots**: 1
- **Mount, this browser**: …
- **Listeners on elements**: …
- **Listeners on the document**

Root 1, a panel.

### Measured against Bits UI

Same UI, production builds, headless Chrome.

Dialog, JavaScript

Svelte Lean  0 B

Bits UI  12.4 kB

Menu, JavaScript 14.2× smaller

Svelte Lean  1.9 kB

Bits UI  27.1 kB

Tabs, JavaScript 3.7× smaller

Svelte Lean  1.5 kB

Bits UI  5.4 kB

Time to mount, a thousand tabs 6.3× faster

Svelte Lean  35.1 ms

Bits UI  220.8 ms

JavaScript heap, a thousand tabs 21.5× smaller

Svelte Lean  2.3 MB

Bits UI  48.9 MB

Median of nine runs; heap after garbage collection. [Open the proof page](https://svelte-lean.vercel.app/proof.md)

## Most of it weighs nothing.

27 of 50 primitives are plain HTML with a stylesheet: they add no JavaScript.

0 B The browser already ships these

- [Accordion](https://svelte-lean.vercel.app/primitives/accordion.md)
- [Alert](https://svelte-lean.vercel.app/primitives/alert.md)
- [Avatar](https://svelte-lean.vercel.app/primitives/avatar.md)
- [Badge](https://svelte-lean.vercel.app/primitives/badge.md)
- [Breadcrumb](https://svelte-lean.vercel.app/primitives/breadcrumb.md)
- [Button](https://svelte-lean.vercel.app/primitives/button.md)
- [Button group](https://svelte-lean.vercel.app/primitives/button-group.md)
- [Card](https://svelte-lean.vercel.app/primitives/card.md)
- [Carousel](https://svelte-lean.vercel.app/primitives/carousel.md)
- [Checkbox](https://svelte-lean.vercel.app/primitives/checkbox.md)
- [Descriptions](https://svelte-lean.vercel.app/primitives/descriptions.md)
- [Dialog](https://svelte-lean.vercel.app/primitives/dialog.md)
- [Empty state](https://svelte-lean.vercel.app/primitives/empty.md)
- [Field](https://svelte-lean.vercel.app/primitives/field.md)
- [Keyboard key](https://svelte-lean.vercel.app/primitives/kbd.md)
- [Meter](https://svelte-lean.vercel.app/primitives/meter.md)
- [Nav](https://svelte-lean.vercel.app/primitives/nav.md)
- [Pagination](https://svelte-lean.vercel.app/primitives/pagination.md)
- [Popover](https://svelte-lean.vercel.app/primitives/popover.md)
- [Progress](https://svelte-lean.vercel.app/primitives/progress.md)
- [Radio group](https://svelte-lean.vercel.app/primitives/radio-group.md)
- [Rating](https://svelte-lean.vercel.app/primitives/rating.md)
- [Scroll area](https://svelte-lean.vercel.app/primitives/scroll-area.md)
- [Separator](https://svelte-lean.vercel.app/primitives/separator.md)
- [Skeleton](https://svelte-lean.vercel.app/primitives/skeleton.md)
- [Steps](https://svelte-lean.vercel.app/primitives/steps.md)
- [Timeline](https://svelte-lean.vercel.app/primitives/timeline.md)

- [Copy](https://svelte-lean.vercel.app/primitives/copy.md)  1.3 kB Tier 1
- [Checkbox group](https://svelte-lean.vercel.app/primitives/checkbox-group.md)  1.5 kB Tier 1
- [Slider](https://svelte-lean.vercel.app/primitives/slider.md)  1.5 kB Tier 1
- [Toast](https://svelte-lean.vercel.app/primitives/toast.md)  1.6 kB Tier 2
- [Toolbar](https://svelte-lean.vercel.app/primitives/toolbar.md)  1.7 kB Tier 1
- [Input](https://svelte-lean.vercel.app/primitives/input.md)  1.8 kB Tier 1
- [Tabs](https://svelte-lean.vercel.app/primitives/tabs.md)  1.8 kB Tier 1
- [Findable](https://svelte-lean.vercel.app/primitives/findable.md)  1.9 kB Tier 1
- [Splitter](https://svelte-lean.vercel.app/primitives/splitter.md)  1.9 kB Tier 2
- [Toggle group](https://svelte-lean.vercel.app/primitives/toggle-group.md)  1.9 kB Tier 1
- [Hover card](https://svelte-lean.vercel.app/primitives/hover-card.md)  2 kB Tier 1
- [Menubar](https://svelte-lean.vercel.app/primitives/menubar.md)  2.1 kB Tier 1
- [Tree](https://svelte-lean.vercel.app/primitives/tree.md)  2.1 kB Tier 1
- [Listbox](https://svelte-lean.vercel.app/primitives/listbox.md)  2.4 kB Tier 1
- [Tooltip](https://svelte-lean.vercel.app/primitives/hint.md)  2.7 kB Tier 1
- [Menu](https://svelte-lean.vercel.app/primitives/menu.md)  2.8 kB Tier 1
- [File drop](https://svelte-lean.vercel.app/primitives/file-drop.md)  3 kB Tier 1
- [Sortable](https://svelte-lean.vercel.app/primitives/sortable.md)  3.8 kB Tier 2
- [Autocomplete](https://svelte-lean.vercel.app/primitives/autocomplete.md)  4 kB Tier 2
- [Calendar](https://svelte-lean.vercel.app/primitives/calendar.md)  4.6 kB Tier 1
- [Select](https://svelte-lean.vercel.app/primitives/select.md)  5 kB Tier 2
- [Date picker](https://svelte-lean.vercel.app/primitives/date-picker.md)  9.5 kB Tier 2

Production build, brotli, including the shared kernel each behavior needs. [All measurements](https://svelte-lean.vercel.app/performance/results.md)

@svelte-lean/query · v0.2.0

## Svelte Lean Query

Server state for Svelte 5: endpoints defined once, a cache keyed by params, invalidation by typed tags and the loading states a screen needs, built on runes.

[Read the documentation](https://svelte-lean.vercel.app/query.md)

- Queries
- Mutations
- Cache
- Invalidation
- Polling
- Realtime

```bash
npm install @svelte-lean/query
```

The bracket is the browser. The square is Svelte Lean.

## Start with the HTML you already know.

```bash
npm install @svelte-lean/primitives
```

- [Read the docs  Philosophy, installation and the architecture.](https://svelte-lean.vercel.app/docs.md)
- [Browse primitives  Every primitive with its tier and contract.](https://svelte-lean.vercel.app/primitives.md)
- [Explore the table  Columns, rows, state, workflows and the API.](https://svelte-lean.vercel.app/table.md)
