Results
Measured numbers only. Every row is read from a file written by a script in this repository and shown with the environment it was taken in and the command that reproduces it. A missing file or key renders as not measured; no value on this page is typed.
On this page
Sizes per entry point
Production output of each package, measured by its own yarn size. The budget column
shows the value the script fails on, where one exists; rows without a budget are recorded for
comparison (the esbuild figures keep helpers behind folded development gates and are not the
quoted number). Method and environment: Methodology.
@svelte-lean/primitives
| Subject | Entry or tool | raw | gzip | brotli | Budget | Status | Notes |
|---|---|---|---|---|---|---|---|
core-only | vite | 1590 B | 841 B | 730 B | none (recorded for comparison) | – | – |
core-only | esbuild | 2461 B | 1247 B | 1094 B | none (recorded for comparison) | – | – |
tabs | vite | 3639 B | 1693 B | 1521 B | 1700 B brotli | within budget | no diagnostics · registration kept |
tabs | esbuild | 4875 B | 2249 B | 2021 B | none (recorded for comparison) | – | diagnostics: __SLEAN_DEBUG__, Svelte Lean Runtime, WeakSet |
menu | vite | 4765 B | 2162 B | 1932 B | 2100 B brotli | within budget | no diagnostics · registration kept |
menu | esbuild | 5830 B | 2661 B | 2399 B | none (recorded for comparison) | – | diagnostics: __SLEAN_DEBUG__, Svelte Lean Runtime, WeakSet |
listbox | vite | 4268 B | 2030 B | 1838 B | 2000 B brotli | within budget | no diagnostics · registration kept |
listbox | esbuild | 5470 B | 2568 B | 2320 B | none (recorded for comparison) | – | diagnostics: __SLEAN_DEBUG__, Svelte Lean Runtime, WeakSet |
combobox | vite | 6855 B | 2849 B | 2564 B | 2900 B brotli | within budget | no diagnostics · registration kept |
combobox | esbuild | 8288 B | 3460 B | 3143 B | none (recorded for comparison) | – | diagnostics: __SLEAN_DEBUG__, Svelte Lean Runtime, WeakSet |
select | vite | 9526 B | 3731 B | 3362 B | 3700 B brotli | within budget | no diagnostics · registration kept |
select | esbuild | 10912 B | 4351 B | 3925 B | none (recorded for comparison) | – | diagnostics: __SLEAN_DEBUG__, Svelte Lean Runtime, WeakSet |
calendar | vite | 10627 B | 4268 B | 3925 B | 4300 B brotli | within budget | no diagnostics · registration kept |
calendar | esbuild | 11806 B | 4815 B | 4418 B | none (recorded for comparison) | – | diagnostics: __SLEAN_DEBUG__, Svelte Lean Runtime, WeakSet |
date-picker | vite | 13726 B | 5364 B | 4912 B | 5400 B brotli | within budget | no diagnostics · registration kept |
date-picker | esbuild | 15377 B | 6098 B | 5594 B | none (recorded for comparison) | – | diagnostics: __SLEAN_DEBUG__, Svelte Lean Runtime, WeakSet |
tooltip | vite | 3165 B | 1473 B | 1297 B | 1400 B brotli | within budget | no diagnostics · registration kept |
tooltip | esbuild | 4341 B | 2011 B | 1787 B | none (recorded for comparison) | – | diagnostics: __SLEAN_DEBUG__, Svelte Lean Runtime, WeakSet |
toast | vite | 3403 B | 1547 B | 1396 B | 1600 B brotli | within budget | no diagnostics · registration kept |
toast | esbuild | 4701 B | 2124 B | 1906 B | none (recorded for comparison) | – | diagnostics: __SLEAN_DEBUG__, Svelte Lean Runtime, WeakSet |
tree | vite | 4817 B | 2139 B | 1919 B | 2100 B brotli | within budget | no diagnostics · registration kept |
tree | esbuild | 5927 B | 2633 B | 2380 B | none (recorded for comparison) | – | diagnostics: __SLEAN_DEBUG__, Svelte Lean Runtime, WeakSet |
range-slider | vite | 2919 B | 1426 B | 1291 B | 1400 B brotli | within budget | no diagnostics · registration kept |
range-slider | esbuild | 3954 B | 1926 B | 1744 B | none (recorded for comparison) | – | diagnostics: __SLEAN_DEBUG__, Svelte Lean Runtime, WeakSet |
number-field | vite | 2519 B | 1228 B | 1082 B | 1200 B brotli | within budget | no diagnostics · registration kept |
number-field | esbuild | 3581 B | 1714 B | 1526 B | none (recorded for comparison) | – | diagnostics: __SLEAN_DEBUG__, Svelte Lean Runtime, WeakSet |
toggle | vite | 1964 B | 1005 B | 888 B | 1000 B brotli | within budget | no diagnostics · registration kept |
toggle | esbuild | 2993 B | 1486 B | 1329 B | none (recorded for comparison) | – | diagnostics: __SLEAN_DEBUG__, Svelte Lean Runtime, WeakSet |
toggle-group | vite | 3734 B | 1756 B | 1569 B | 1800 B brotli | within budget | no diagnostics · registration kept |
toggle-group | esbuild | 4944 B | 2296 B | 2063 B | none (recorded for comparison) | – | diagnostics: __SLEAN_DEBUG__, Svelte Lean Runtime, WeakSet |
toolbar | vite | 3459 B | 1671 B | 1494 B | 1700 B brotli | within budget | no diagnostics · registration kept |
toolbar | esbuild | 4563 B | 2167 B | 1940 B | none (recorded for comparison) | – | diagnostics: __SLEAN_DEBUG__, Svelte Lean Runtime, WeakSet |
splitter | vite | 4355 B | 1881 B | 1683 B | 1900 B brotli | within budget | no diagnostics · registration kept |
splitter | esbuild | 5499 B | 2428 B | 2178 B | none (recorded for comparison) | – | diagnostics: __SLEAN_DEBUG__, Svelte Lean Runtime, WeakSet |
context-menu | vite | 3286 B | 1574 B | 1409 B | 1600 B brotli | within budget | no diagnostics · registration kept |
context-menu | esbuild | 4323 B | 2056 B | 1856 B | none (recorded for comparison) | – | diagnostics: __SLEAN_DEBUG__, Svelte Lean Runtime, WeakSet |
file-drop | vite | 2627 B | 1244 B | 1107 B | 1300 B brotli | within budget | no diagnostics · registration kept |
file-drop | esbuild | 3706 B | 1742 B | 1562 B | none (recorded for comparison) | – | diagnostics: __SLEAN_DEBUG__, Svelte Lean Runtime, WeakSet |
hover-card | vite | 3312 B | 1530 B | 1353 B | 1500 B brotli | within budget | no diagnostics · registration kept |
hover-card | esbuild | 4464 B | 2052 B | 1828 B | none (recorded for comparison) | – | diagnostics: __SLEAN_DEBUG__, Svelte Lean Runtime, WeakSet |
menubar | vite | 3464 B | 1623 B | 1457 B | 1700 B brotli | within budget | no diagnostics · registration kept |
menubar | esbuild | 4495 B | 2097 B | 1886 B | none (recorded for comparison) | – | diagnostics: __SLEAN_DEBUG__, Svelte Lean Runtime, WeakSet |
native-only | vite | 11810 B | 3207 B | 2681 B | none (recorded for comparison) | – | no runtime |
@svelte-lean/core
| Subject | Entry or tool | raw | gzip | brotli | Budget | Status | Notes |
|---|---|---|---|---|---|---|---|
production | esbuild | 4429 B | 2113 B | 1927 B | 2500 B gzip | within budget | diagnostics: __SLEAN_DEBUG__, Svelte Lean Runtime, validate, WeakSet, is not a routed event type |
default | esbuild | 4632 B | 2197 B | 1990 B | 2500 B gzip | within budget | diagnostics: console.warn, __SLEAN_DEBUG__, Svelte Lean Runtime, validate, WeakSet, is not a routed event type |
consumer | vite | 1936 B | 994 B | 882 B | 2500 B gzip | within budget | no diagnostics |
@svelte-lean/table
| Subject | Entry or tool | raw | gzip | brotli | Budget | Status | Notes |
|---|---|---|---|---|---|---|---|
renderer | dist/index.js | 64638 B | 20031 B | 17886 B | 22000 B gzip | within budget | – |
headless | dist/core.js | 5338 B | 2475 B | 2280 B | 2700 B gzip | within budget | – |
engine | dist/table.svelte.js | 8416 B | 3494 B | 3204 B | 3600 B gzip | within budget | – |
grouping | dist/grouping.js | 4675 B | 2148 B | 1963 B | 2400 B gzip | within budget | – |
pivot | dist/pivot.js | 948 B | 526 B | 470 B | 600 B gzip | within budget | – |
editing | dist/editing.js | 1367 B | 707 B | 617 B | 800 B gzip | within budget | – |
csv | dist/export.js | 1220 B | 741 B | 646 B | 850 B gzip | within budget | – |
clipboard | dist/clipboard.js | 1721 B | 895 B | 817 B | 1000 B gzip | within budget | – |
server | dist/server.js | 561 B | 369 B | 310 B | 425 B gzip | within budget | – |
state | dist/state.js | 1793 B | 796 B | 711 B | 900 B gzip | within budget | – |
styles | dist/style.css | 30608 B | 6665 B | 5704 B | 7300 B gzip | within budget | – |
@svelte-lean/styles
| Subject | Entry or tool | raw | gzip | brotli | Budget | Status | Notes |
|---|---|---|---|---|---|---|---|
accordion.css | – | 3585 B | 816 B | 660 B | none (recorded for comparison) | – | minified before compression |
alert-dialog.css | – | 2814 B | 559 B | 457 B | none (recorded for comparison) | – | minified before compression |
alert.css | – | 5201 B | 798 B | 665 B | none (recorded for comparison) | – | minified before compression |
autocomplete.css | – | 3065 B | 594 B | 482 B | none (recorded for comparison) | – | minified before compression |
avatar.css | – | 2726 B | 545 B | 437 B | none (recorded for comparison) | – | minified before compression |
badge.css | – | 2086 B | 488 B | 387 B | none (recorded for comparison) | – | minified before compression |
base.css | – | 1789 B | 360 B | 290 B | none (recorded for comparison) | – | minified before compression |
breadcrumb.css | – | 3023 B | 647 B | 532 B | none (recorded for comparison) | – | minified before compression |
button-group.css | – | 3438 B | 503 B | 404 B | none (recorded for comparison) | – | minified before compression |
button.css | – | 6825 B | 1013 B | 863 B | none (recorded for comparison) | – | minified before compression |
calendar.css | – | 9719 B | 1312 B | 1121 B | none (recorded for comparison) | – | minified before compression |
card.css | – | 4365 B | 857 B | 686 B | none (recorded for comparison) | – | minified before compression |
carousel.css | – | 6672 B | 978 B | 841 B | none (recorded for comparison) | – | minified before compression |
checkbox.css | – | 3496 B | 764 B | 615 B | none (recorded for comparison) | – | minified before compression |
color-field.css | – | 3741 B | 602 B | 488 B | none (recorded for comparison) | – | minified before compression |
combobox.css | – | 1206 B | 178 B | 144 B | none (recorded for comparison) | – | minified before compression |
context-menu.css | – | 1101 B | 246 B | 219 B | none (recorded for comparison) | – | minified before compression |
control.css | – | 16971 B | 1960 B | 1698 B | none (recorded for comparison) | – | minified before compression |
date-field.css | – | 2929 B | 654 B | 550 B | none (recorded for comparison) | – | minified before compression |
date-picker.css | – | 4889 B | 812 B | 687 B | none (recorded for comparison) | – | minified before compression |
descriptions.css | – | 3261 B | 554 B | 451 B | none (recorded for comparison) | – | minified before compression |
dialog.css | – | 4571 B | 898 B | 728 B | none (recorded for comparison) | – | minified before compression |
disclosure.css | – | 2433 B | 638 B | 509 B | none (recorded for comparison) | – | minified before compression |
drawer.css | – | 6867 B | 1152 B | 970 B | none (recorded for comparison) | – | minified before compression |
empty.css | – | 3302 B | 663 B | 553 B | none (recorded for comparison) | – | minified before compression |
field.css | – | 2468 B | 455 B | 368 B | none (recorded for comparison) | – | minified before compression |
file-drop.css | – | 3109 B | 659 B | 548 B | none (recorded for comparison) | – | minified before compression |
file-field.css | – | 3735 B | 702 B | 598 B | none (recorded for comparison) | – | minified before compression |
hover-card.css | – | 3000 B | 621 B | 516 B | none (recorded for comparison) | – | minified before compression |
index.css | – | 1854 B | 371 B | 309 B | none (recorded for comparison) | – | minified before compression |
input.css | – | 4163 B | 680 B | 560 B | none (recorded for comparison) | – | minified before compression |
kbd.css | – | 1259 B | 373 B | 297 B | none (recorded for comparison) | – | minified before compression |
listbox.css | – | 5165 B | 917 B | 752 B | none (recorded for comparison) | – | minified before compression |
menu.css | – | 5619 B | 993 B | 834 B | none (recorded for comparison) | – | minified before compression |
menubar.css | – | 2485 B | 599 B | 498 B | none (recorded for comparison) | – | minified before compression |
meter.css | – | 3572 B | 486 B | 389 B | none (recorded for comparison) | – | minified before compression |
number-field.css | – | 6000 B | 987 B | 837 B | none (recorded for comparison) | – | minified before compression |
otp-field.css | – | 4663 B | 818 B | 696 B | none (recorded for comparison) | – | minified before compression |
pagination.css | – | 4981 B | 891 B | 755 B | none (recorded for comparison) | – | minified before compression |
popover.css | – | 4215 B | 559 B | 465 B | none (recorded for comparison) | – | minified before compression |
progress.css | – | 2964 B | 601 B | 514 B | none (recorded for comparison) | – | minified before compression |
radio-group.css | – | 4505 B | 834 B | 688 B | none (recorded for comparison) | – | minified before compression |
range-slider.css | – | 5305 B | 801 B | 689 B | none (recorded for comparison) | – | minified before compression |
rating.css | – | 4803 B | 926 B | 746 B | none (recorded for comparison) | – | minified before compression |
scroll-area.css | – | 4006 B | 561 B | 457 B | none (recorded for comparison) | – | minified before compression |
segmented.css | – | 4292 B | 848 B | 691 B | none (recorded for comparison) | – | minified before compression |
select.css | – | 13417 B | 1685 B | 1456 B | none (recorded for comparison) | – | minified before compression |
separator.css | – | 1135 B | 285 B | 219 B | none (recorded for comparison) | – | minified before compression |
skeleton.css | – | 2687 B | 546 B | 459 B | none (recorded for comparison) | – | minified before compression |
slider.css | – | 5197 B | 777 B | 624 B | none (recorded for comparison) | – | minified before compression |
spinner.css | – | 2392 B | 510 B | 419 B | none (recorded for comparison) | – | minified before compression |
splitter.css | – | 4454 B | 779 B | 657 B | none (recorded for comparison) | – | minified before compression |
steps.css | – | 5826 B | 1047 B | 882 B | none (recorded for comparison) | – | minified before compression |
switch.css | – | 3708 B | 771 B | 626 B | none (recorded for comparison) | – | minified before compression |
tabs.css | – | 4147 B | 835 B | 678 B | none (recorded for comparison) | – | minified before compression |
tag.css | – | 3062 B | 731 B | 592 B | none (recorded for comparison) | – | minified before compression |
timeline.css | – | 4296 B | 750 B | 622 B | none (recorded for comparison) | – | minified before compression |
toast.css | – | 4737 B | 952 B | 794 B | none (recorded for comparison) | – | minified before compression |
toggle-group.css | – | 4030 B | 787 B | 646 B | none (recorded for comparison) | – | minified before compression |
toggle.css | – | 4072 B | 731 B | 603 B | none (recorded for comparison) | – | minified before compression |
tokens.css | – | 18068 B | 2204 B | 1895 B | none (recorded for comparison) | – | minified before compression |
toolbar.css | – | 2370 B | 481 B | 399 B | none (recorded for comparison) | – | minified before compression |
tooltip.css | – | 2604 B | 543 B | 443 B | none (recorded for comparison) | – | minified before compression |
tree.css | – | 4363 B | 856 B | 719 B | none (recorded for comparison) | – | minified before compression |
index.css (resolved) | – | 280760 B | 20765 B | 16880 B | 21600 B gzip | within budget | minified before compression |
What a consumer ships
Five small applications consume the packages the way an installed consumer would and are built
in production mode. A plugin isolates every @svelte-lean/* module into one chunk
and Svelte's runtime into another, so the Svelte Lean bytes of a page can be read without
Svelte's in them. Assertions are the expect.json checks of each fixture (module graph,
forbidden strings, manifest).
| Fixture | Uses | Svelte Lean chunk, brotli | gzip | raw | Svelte runtime, brotli | CSS, brotli | Svelte Lean modules | Assertions |
|---|---|---|---|---|---|---|---|---|
combobox-only | – | 2564 B | 2849 B | 6855 B | 8710 B | 3695 B | 14 | 48 passed |
date-picker-only | – | 5446 B | 5935 B | 15676 B | 12207 B | 4777 B | 21 | 53 passed |
listbox-only | – | 1838 B | 2030 B | 4268 B | 8710 B | 2704 B | 14 | 46 passed |
manual-registration | tabs markup, register module imported by hand | 1521 B | 1693 B | 3639 B | 8710 B | 2652 B | 13 | 42 passed |
native-only | button, dialog, popover markup and styles | 0 B | 0 B | 0 B | 8710 B | 3565 B | 0 | 31 passed |
select-only | – | 3362 B | 3731 B | 9526 B | 10119 B | 4546 B | 14 | 48 passed |
table-basic | <DataTable /> and its stylesheet | 16829 B | 18900 B | 52658 B | 15916 B | 5402 B | 8 | 46 passed |
tabs-and-menu | tabs and menu markup | 2351 B | 2611 B | 6209 B | 8710 B | 3944 B | 17 | 43 passed |
tabs-only | tabs markup, discovered by the plugin | 1521 B | 1693 B | 3639 B | 8710 B | 2652 B | 13 | 43 passed |
Method: Production `vite build` per fixture with Vite defaults (esbuild minify, modulepreload polyfill). Sizes are the emitted JavaScript and CSS files: raw bytes, gzip level 9, brotli quality 11 (node:zlib). "svelteLean" is the svelte-lean chunk that the fixture plugin isolates for every @svelte-lean/* module and "svelteRuntime" the svelte-runtime chunk for Svelte's runtime (both include chunk import/export bindings); 0 B means no such chunk was emitted. "modules.svelteLean" lists rendered @svelte-lean/* modules with their pre-minification rendered length. Environment: node
v22.23.3,vite
7.3.6,svelte
5.57.1,@sveltejs/vite-plugin-svelte
6.2.4. Date: not recorded in the file. Command: yarn test:fixtures.
Listeners
The listener claim has no number in a file: it is an exact assertion in the browser suite, that
the per-type listener counts for a thousand tabs roots equal those for one root, on two
independent accounts. What this page can show is the same two accounts taken live. The specimen
below is a real tabs root driven by the shared behavior; the panel under it reads the runtime's
own account and the independent count of every addEventListener call on this page. Mount
a hundred roots, then compare the readings.
- Runtime
- Read from the page after it loads; requires JavaScript.
The proof page mounts one, a hundred or a thousand roots on demand and
records a reading for each count. The gate itself is listeners.spec.ts;
command: yarn workspace @svelte-lean/playground test:e2e --project=chromium tests/primitives/listeners.spec.ts. Two related counts are recorded in files:
| Subject | Value | Method | File |
|---|---|---|---|
| DOM nodes with a thousand tabs roots | 8045 | document.getElementsByTagName("*").length after load | apps/playground/results/bench.json |
| JavaScript event listeners on the page after five mount and unmount cycles | 28 | Performance.getMetrics JSEventListeners at baseline and after the last cycle | apps/playground/results/stress.json |
Timings
Startup and interaction entries, each the median of five fresh page loads with every sample recorded. Minimum and maximum are shown so the spread is visible: five samples on one machine give a median, not a distribution, and a run on another machine gives another number. Startup and interaction are never combined into one score.
| Subject | Median | Min | Max | p95 | Samples | Method |
|---|---|---|---|---|---|---|
table.1000-rows.mount | 283.8 ms | 267.3 ms | 342.8 ms | 342.8 ms | 5 | component init to the second animation frame after onMount, client render of the whole table (ssr=false); median of 5 loads |
table.1000-rows.render | 231.4 ms | 205.8 ms | 378.1 ms | 378.1 ms | 5 | unmount + mount of the DataTable via {#key}, tick() then two animation frames; median of 5 |
table.1000-rows.sort | 114.1 ms | 110.7 ms | 117.7 ms | 117.7 ms | 5 | header button click (ascending by revenue) to the second animation frame; median of 5 |
table.10000-rows.mount | 3907.1 ms | 3105.6 ms | 5984.2 ms | 5984.2 ms | 5 | component init to the second animation frame after onMount, client render of the whole table (ssr=false); median of 5 loads |
table.10000-rows.render | 3806.9 ms | 2946.1 ms | 4554.2 ms | 4554.2 ms | 5 | unmount + mount of the DataTable via {#key}, tick() then two animation frames; median of 5 |
table.10000-rows.sort | 1928.4 ms | 1385.3 ms | 2142.4 ms | 2142.4 ms | 5 | header button click (ascending by revenue) to the second animation frame; median of 5 |
tabs.1000-roots.dom-content-loaded | 73.8 ms | 23 ms | 84.4 ms | 84.4 ms | 5 | PerformanceNavigationTiming.domContentLoadedEventEnd of a fresh page.goto; median of 5 loads |
tabs.1000-roots.load | 74.2 ms | 23 ms | 84.9 ms | 84.9 ms | 5 | PerformanceNavigationTiming.loadEventEnd of a fresh page.goto; median of 5 loads |
tabs.1000-roots.time-to-interactive | 98.8 ms | 66.1 ms | 119.3 ms | 119.3 ms | 5 | performance.now() in onMount of the client-rendered page: 1000 roots in the document and the behavior registered; median of 5 loads |
tabs.1000-roots.first-interaction | 1.6 ms | 1.3 ms | 2.5 ms | 2.5 ms | 5 | performance.now() around trigger.click() on root 500 right after load (synchronous routing + DOM writes); median of 5 loads |
tabs.1000-roots.repeat-interaction | 0.7 ms | 0.7 ms | 1.1 ms | 1.1 ms | 5 | performance.now() around a second trigger.click() on root 900; median of 5 loads |
tabs.1000-roots.dom-nodes | 8045 | 8045 | 8045 | 8045 | 5 | document.getElementsByTagName("*").length after load |
Environment: chromium 153.0.8010.53, darwin
27.0.0
arm64, Apple M2, 8 cores, 16 GiB, Node v22.23.3, production build, headless.
Date: 2026-09-27T20:46:17.407Z. Command: yarn bench:publish.
Memory after stress cycles
A thousand tabs roots mounted and unmounted five times, a menu opened and closed two hundred
times, and one combobox root opened with ArrowDown and closed with Escape two hundred times (a
Tier 2 session per cycle; the number of scoped document pointerdown listeners installed
is recorded next to the JSEventListeners count): heap after forced garbage collection, DOM nodes and
listeners, against a baseline taken after a warm-up cycle. The tolerance for growth is stated in each
entry's method. This project runs in the nightly workflow, not on every pull request.
| Subject | Median | Min | Max | p95 | Samples | Method |
|---|---|---|---|---|---|---|
stress.tabs.mount-unmount.heap-fresh | 2136940 bytes | 2136940 bytes | 2136940 bytes | not measured | 1 | JSHeapUsedSize after two forced GCs on /primitives/tabs/many?n=1 right after load |
stress.tabs.mount-unmount.heap-baseline | 2665560 bytes | 2665560 bytes | 2665560 bytes | not measured | 1 | JSHeapUsedSize after two forced GCs, n=1, after one warm-up cycle 1 → 1000 → 1 |
stress.tabs.mount-unmount.heap-peak | 11787304 bytes | 11650340 bytes | 11864060 bytes | 11864060 bytes | 5 | JSHeapUsedSize after two forced GCs with 1000 roots mounted and interacted with, one sample per cycle |
stress.tabs.mount-unmount.heap-per-cycle | 8889316 bytes | 8828724 bytes | 8984780 bytes | 8984780 bytes | 5 | heap-peak minus the heap after the previous cleanup: what 1000 roots cost, one sample per cycle |
stress.tabs.mount-unmount.heap-after-cleanup | 2974744 bytes | 2846752 bytes | 3035596 bytes | 3035596 bytes | 5 | JSHeapUsedSize after two forced GCs back at n=1, one sample per cycle |
stress.tabs.mount-unmount.heap-growth | 380208 bytes | 380208 bytes | 380208 bytes | not measured | 1 | heap after 5 cycles minus baseline; tolerance max(2 MiB, 15 % of baseline) = 2097152 B |
stress.tabs.mount-unmount.nodes-baseline | 310 | 310 | 310 | not measured | 1 | Performance.getMetrics Nodes at n=1 after the warm-up cycle |
stress.tabs.mount-unmount.nodes-after-cleanup | 310 | 310 | 310 | 310 | 5 | Performance.getMetrics Nodes back at n=1, one sample per cycle; allowance 100 above baseline |
stress.tabs.mount-unmount.js-event-listeners | 28 | 28 | 28 | 28 | 2 | Performance.getMetrics JSEventListeners at baseline and after the last cycle |
stress.menu.open-close.heap-baseline | 2084788 bytes | 2084788 bytes | 2084788 bytes | not measured | 1 | JSHeapUsedSize after two forced GCs on /primitives/menu after one open/close cycle |
stress.menu.open-close.heap-after | 2138688 bytes | 2138688 bytes | 2138688 bytes | not measured | 1 | JSHeapUsedSize after two forced GCs after 200 open/close cycles |
stress.menu.open-close.heap-growth | 53900 bytes | 53900 bytes | 53900 bytes | not measured | 1 | heap after minus baseline; tolerance max(2 MiB, 15 % of baseline) = 2097152 B |
stress.menu.open-close.nodes | 267 | 267 | 267 | 267 | 2 | Performance.getMetrics Nodes at baseline and after the cycles |
stress.menu.open-close.cycles-focused-inside | 200 | 200 | 200 | not measured | 1 | cycles (of 200) in which the first item had focus when Escape was sent |
stress.combobox.open-close.heap-baseline | 2379528 bytes | 2379528 bytes | 2379528 bytes | not measured | 1 | JSHeapUsedSize after two forced GCs on /primitives/combobox after one open/close cycle |
stress.combobox.open-close.heap-after | 2542684 bytes | 2542684 bytes | 2542684 bytes | not measured | 1 | JSHeapUsedSize after two forced GCs after 200 open/close cycles (ArrowDown, Escape) of one Tier 2 root |
stress.combobox.open-close.heap-growth | 163156 bytes | 163156 bytes | 163156 bytes | not measured | 1 | heap after minus baseline; tolerance max(2 MiB, 15 % of baseline) = 2097152 B |
stress.combobox.open-close.nodes | 1006 | 1006 | 1006 | 1006 | 2 | Performance.getMetrics Nodes at baseline and after the cycles |
stress.combobox.open-close.js-event-listeners | 37 | 37 | 37 | 37 | 2 | Performance.getMetrics JSEventListeners at baseline and after the cycles; a retained session listener would raise it |
stress.combobox.open-close.session-listeners-installed | 200 | 200 | 200 | not measured | 1 | document pointerdown installations recorded by the wrapped addEventListener during 200 cycles: one scoped listener per open session |
stress.combobox.open-close.cycles-active-while-open | 200 | 200 | 200 | not measured | 1 | cycles (of 200) in which an option was active while the popup was open |
Environment: chromium 153.0.8010.53, darwin
27.0.0
arm64, Apple M2, 8 cores, 16 GiB, Node v22.23.3, production build, headless.
Date: 2026-09-27T20:46:35.800Z. Command: yarn bench:publish.
Table with 1000 rows
The specimen the timings above are taken from, rendered on demand with every row in the document: no pagination and no virtualization, deliberately. The two readings under the table are taken in your browser when the specimen mounts and when you re-render it; they are readings, not published numbers, and change with the machine.
The table mounts when you ask for it and requires JavaScript; the prerendered HTML does not carry its seven thousand cells.
<script lang="ts">
import { DataTable, type Column } from '@svelte-lean/table';
import '@svelte-lean/table/style.css';
import { rows, type Row } from './rows'; // one thousand generated rows
const columns: Column<Row>[] = [
{ id: 'name', header: 'Name' },
{ id: 'email', header: 'Email' },
{ id: 'team', header: 'Team' },
{ id: 'region', header: 'Region' },
{ id: 'status', header: 'Status' },
{ id: 'revenue', header: 'Revenue', align: 'end' },
{ id: 'joined', header: 'Joined' }
];
</script>
<!-- Every row is in the document: no pagination, no virtualization. -->
<DataTable
data={rows}
{columns}
getRowId={(row) => row.id}
label="One thousand rows"
pagination={false}
stickyHeader
height="24rem"
/>Source
- Size scripts: primitives, core, table, styles.
- Fixtures: fixtures/ with the runner run.mjs and the assertion helper assert.mjs.
- Benchmarks: tabs.bench.spec.ts, table.bench.spec.ts; stress: tests/stress.
- Listener gate: listeners.spec.ts; the independent counter in packages/test-utils.
- Claim registry: docs/proof/claims.md; the audit of the checklist: docs/proof.