A comparison of two window layout engines for a trading terminal: operation timings, scaling, memory, DOM, bundle size and features. Plus the results of the dockview 5.2 → 8.4 upgrade.
dockview 8.4.0CustomLayoutChromium 153.0.8010.12 headless · M3 Pro3 passes × CPU ×1 and ×4commit a143bbfa + uncommitted changes
01Summary
There is no clear winner. CustomLayout is several times faster at heavy lifecycle operations on large layouts (mount, restore, clear, splitter release). dockview is faster at small, frequent operations (splitter drag step, serialization, panel removal and moving light panels in large trees, first tab open) by 2–20× or more, but in absolute terms that is fractions of a millisecond to a few ms at ×1 (up to ~24 ms at ×4); moving heavy panels is only ×1.1–1.23. Under comparable load (flat-20 with heavy panels) the engines are equal; at size 4 the difference is a few ms.
Mounting 200 heavy panels, ×1
279 / 122 ms
CustomLayout is 2.3× faster, but keeps 20 live panels versus 200
Snapshot restore, 200 heavy, ×1
539 / 137 ms
CL / DV = 0.25×; both engines mount new ids
Splitter step, 200 heavy, ×1
0.42 / 1.99 ms
dockview is 4.7× faster; both are well under the 16.7 ms frame budget
Bundle, JS gzip
86.3 KB / 14.2 KB
CustomLayout is 6.1× smaller
CustomLayout is faster
Mount and restore with ≥ 20 heavy panels (except flat-20): from ×0.81–0.82 (mount, 20) to ×0.25–0.28 (restore, 200), the same at ×1 and ×4
Clear already wins at size 4 (×0.33–0.65)
Clear at ≥ 20: ×0.06–0.12 (240 → 13.3 ms at 200)
Splitter release, heavy panels: ×0.03–0.07 (46.9 → 2.5 ms at 200); with light panels, from parity to ×0.59–0.64 at 100–200 and ×4
Forced resize ×0.50–0.65 (heavy; the absolute gain is fractions of a ms, up to 1.9 ms at ×4); mount cycles ×0.61–0.67 (heavy; parity with light panels)
Tab click: visible latency is one frame lower (dockview defers activation to rAF)
At ×4 with 100–200 heavy panels, real drag is smoother: half as many dropped frames (84–89 vs 185); median frame 33 vs 50 ms, but it is quantized to frames and the difference does not pass the significance criterion
dockview is faster
Splitter drag step: 2–5.6×
Serialization: ~10× (11 vs 115 µs at 200), since getLayout makes a deep copy
Moving a panel in large trees: ×1.23 (heavy), ×4.3 (light, 200); in CustomLayout this is a full config reload
Removing a single panel with ≥ 50 panels: ~18–23× for heavy (0.27 vs 6 ms at 200), 3.4–7.8× for light; with 4–20 heavy panels the difference is not significant. The sharp drop in dockview's median from ~4.5 to ~0.25 ms at ≥ 50 has not been investigated (p95 is ~9–10 ms for both)
First tab open (tabs-20): in CustomLayout this is a lazy mount, 2.0–7.4 ms at ×1 (up to 23.6 ms at ×4) vs < 0.3 ms
Cold mount of 200 light panels: ×1.13
Real drag at ×4 with 20 heavy panels: half as many dropped frames (39 vs 80.5); at 50 the median frame is 16.7 vs 25 ms, but dropped frames are equal (88.5 vs 82), and the difference in median frame is not significant by the criterion
Parity
flat-20 mount (same number of mounted panels): 108.5 / 108.5 ms
Mount and restore at size 4, heavy panels: 4–7 % difference. With light panels CustomLayout is formally significantly faster by 14–28 %, but in absolute terms that is 0.7–4 ms
Tab switch via API, heavy panels: ×0.89–1.03
Moving heavy panels at 20–50: ×0.99–1.09 (with light panels dockview is faster from 20 already at ×4)
Real drag at ×1: both hold 60 fps at all sizes
Where CustomLayout's advantage comes from. Mostly architectural: CustomLayout mounts only tabs that have been visible at least once, while dockview creates a component for every panel. With 200 heavy panels, 20 stay live versus 200; on tabs-20, 2 versus 21. Where the number of mounted panels is the same (flat-20), heavy-panel mount time matches within 2 % (light: 4–10 % in CustomLayout's favor). For a real terminal with many hidden tabs this is a fair advantage, but it does not mean the layout code itself is faster.
Statistical significance. Out of 240 comparisons on ranked metrics (all sizes, both panel types, ×1 and ×4): 122 CustomLayout faster, 69 dockview faster, 28 parity (difference < 10 %), 21 not significant. "Significant" here means the faster engine won in each of the 3 passes and the interquartile ranges of the pooled samples do not overlap. This is a heuristic, not a formal test: with n = 6 samples per point (more for some metrics) and 3 passes, p-values were not computed. Multi-fold differences are robust; 10–25 % differences at small sizes are on the edge of noise.
What this means in practice. All of CustomLayout's losses in frequent operations (splitter step ≤ 2 ms at ×1, serialization ≤ 0.5 ms) fit within the frame budget even at ×4 with 200 panels (step 9.5 ms). The exception is opening a heavy tab for the first time at ×4 (lazy mount, 23.6 ms): roughly one dropped frame. The wins, meanwhile, fall on operations users notice: opening a workspace (hundreds of ms at ×4) and splitter release (185 → 12 ms at ×4/200). The decision should be based not on speed but on features (see section 09) and maintenance cost.
02Environment and methodology
Machine
Apple M3 Pro, 12 cores, 18 GB, AC power, battery 100%
All /api/* are mocked; only 6 x GET /user went out (mocked 401); non-GET requests: 0; external: 0
How it is measured. The route /layout-benchmark mounts both engines in a 1600×1000 stage and runs identical scenarios through adapters. For each operation it records:
syncMs — the synchronous part of the operation until control returns (including the Vue flush) — the primary cost metric;
readyMs — when the DOM reached the target state (polled in rAF and after a frame) — quantized to frames;
Two panel types: light (a nearly empty component) and heavy (substantial DOM and work on mount). CPU throttling via CDP: ×1 and ×4 (simulating a slow machine). 3 passes per throttling level, each in a fresh page; engine order alternates between passes.
Aggregation. The chart bar is the median of per-pass medians; the whisker is the p95 of the pooled samples. With n = 6, p95 is effectively the maximum. A CL / DV ratio < 1 means CustomLayout is faster.
Layout sizes
Key
Panels
Groups
Tabs per group
Depth
Branching
4
4
4
1
2
2
20
20
10
2
3
3
flat-20
20
20
1
3
3
50
50
10
5
3
3
100
100
20
5
3
3
200
200
20
10
3
3
tabs-20
21
2
20
1
2
Iteration count reduced
With default settings one ×1 pass took ~30 min and ×4 about three times longer; the full run would have taken ~5 h. Iterations were reduced to fit in ~80 min. This widens confidence intervals, especially for small values at size 4.
Parameter
Default
Used
lifecycleIterations
10
2
operationIterations
30
6
warmup
3
1
blocks
5
2
cycles
20
8
dragIterations
3
2
serializeCount
1000
300
trustedRepeats
5
2
Data quality checks
Completeness: 2344 aggregates, no NaN or empty values; both engines passed all scenarios; all real drags were verified (2/2 per engine/size/variant/pass).
Spread: for 19 of 480 points on ranked metrics (16 metrics × size × panel type × CPU × engine), per-pass medians differ by more than 1.6×; all but one are values < 3 ms, mostly at sizes 4 and 20. The only real outlier: restore-same-ids, CustomLayout, 100 heavy, ×4 — 57.9 ms in pass 1 vs 7.4 ms in the other two (the median of medians is unaffected).
Recheck: restore and remove-all at sizes 4 and 100 at ×4, 3 passes of 5 iterations: the outlier gave 7.55 ms (CV 0.06); 41 of 48 values are within 10 % of the main run, the other 7 differ by 13–32 % (mostly CustomLayout: restore-same-ids and restore at size 4, clear and remove-all at 100; plus dockview clear at size 4).
Uninvestigated oddities: tab-switch-api dockview light is faster at 4x (0.78 ms) than at 1x (1.51 ms), consistent across passes; remove-sequential perRemoveSyncMs dockview heavy drops from ~4.5 ms (size 20) to ~0.25 ms (size >=50) while its batched syncMs grows to 887 ms at 100 (4x): per-removal cost there is dominated by hidden tab panels.
03Caveats and fairness of the comparison
A methodology review found 9 issues; all were fixed before the final run. Below is what was fixed and what remains a limitation.
Fixed before the run
restore did different work. CustomLayout stores panels by id, so reloading the same snapshot is nearly a no-op. Now restore-replace loads a snapshot with new ids (both engines mount N panels); the old variant was moved to restore-same-ids.
readyMs lagged by a frame for work deferred to rAF (dockview's ResizeObserver). Added a recheck after the frame: dockview resize-observed 33.5 → 18.3 ms.
readyMs was presented as engine cost. It is now explicitly marked as frame-quantized and is not ranked.
remove-sequential compared batched work. Added a comparable metric perRemoveSyncMs.
Fixed engine order in mount-cycles. Each engine now goes first once per pass.
The CDP heap check mixed engines. Now done separately per engine, with alternating order.
Long tasks / TBT ignored the operation's own task. They are now matched by overlap with the window.
Real drag ignored the axis. The axis is now taken from prepare().
Remaining limitations
Mount counts differ by design: dockview creates a component for every tab, CustomLayout mounts only active tabs, lazily. Compare flat-20 with 20 and read alivePanels next to the timings.
CustomLayout has no fine-grained API for activate, move and add-to-group: those paths are getLayout → helper → loadLayout (a full reload), exactly as the app does it, and are not equivalent to dockview calls.
CustomLayout removeComponent refuses to remove the last remaining panel; the adapter falls back to clearLayout for it.
Headless frame times are indicative. Rank on syncMs, perRemoveSyncMs, stepMs, commitMs and serializeUs, not on readyMs or paintMs: both are quantized to display frames and mostly measure vsync wait.
readyMs is polled at each rAF and again in a task after that frame, so rAF-deferred work is seen in the frame it runs in. Read it together with framesToSettle (the syncMs extra), never as engine cost.
resize-observed: dockview lays out one frame later by design (ResizeObserver → rAF → layout), so its readyMs carries one extra frame of idle time; resize-forced isolates the layout cost. syncMs is only meaningful where readyInSync is 1.
tab-switch-warm: dockview activates on pointerdown and defers it one rAF (HTML5 DnD on); CustomLayout activates on click. Both get the same pointerdown → pointerup → click sequence. Its readyMs is user-visible latency in frames, not work; compare engine cost on tab-switch-api syncMs.
restore-replace loads a snapshot of the same shape with disjoint ids, so both engines unmount N and mount N panels. restore-same-ids reloads identical ids: CustomLayout keeps its id-keyed panels mounted and only diffs the tree, dockview fromJSON rebuilds every panel. Check the mounts extra before reading it as a speed difference.
remove-sequential removes all N panels in one synchronous block: dockview updates the DOM on every removePanel, CustomLayout replaces a reactive config N times and renders once. It measures batched API cost; perRemoveSyncMs (each removal flushed on its own) is the like-for-like per-operation metric.
mount-cycles runs each engine twice per pass in opposite order (each engine goes first once); heapDeltaBytes therefore has two samples per pass.
add-k appends 20 root groups to a 4-group tree; past ~16 root groups dockview clamps groups at its 100 px minimum while CustomLayout keeps shrinking them.
Reduced iterations (see above): only differences ≥ 1.5× are worth ranking; 10–25 % differences at size 4 are within noise.
Headless Chromium without GPU compositing: absolute numbers are lower than on users' real hardware; the ratios are what matter.
Synthetic panels are not real terminal widgets (TradingView charts, tables with data streams).
04Scenarios
Each metric has two charts (CPU ×1 and ×4) and a table. The bar is the median, the whisker is p95, and under each category is the CL / DV ratio (color marks the significant winner, gray means parity or noise). The toggle below switches the panel type in all charts.
On narrow screens the value labels above bars are hidden; exact numbers are in the tables below the charts and in tooltips.
dockviewCustomLayout
Scenario list
1Cold mount cold-mount · syncMs
Empty engine → loading a tree of N panels, synchronous part until control returns. flat-20 is 20 groups with one tab each (same number of mounted panels in both engines). ranked metric
CPU ×1CPU ×4
Table: heavy panels
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
4
×1
23.9
25.9
23.2
1.08
22.7
24.2
21.6
0.95
0.95×
parity
6
4
×4
85.5
86.8
84.8
0.74
82.3
84.4
81.3
1.29
0.96×
parity
6
20
×1
62.7
64.4
61.1
1.28
51.6
53.1
50.1
1.12
0.82×
CL faster
6
20
×4
246
257
235
8.63
200
204
196
3.18
0.81×
CL faster
6
flat-20
×1
108
111
102
3.63
109
111
101
3.54
1.00×
parity
6
flat-20
×4
420
437
404
13.8
410
429
398
13.6
0.98×
parity
6
50
×1
88.5
89.4
87.1
0.89
54.5
55.3
53.6
0.74
0.62×
CL faster
6
50
×4
355
358
343
5.33
208
212
206
2.37
0.58×
CL faster
6
100
×1
196
197
195
0.60
114
118
109
3.95
0.58×
CL faster
6
100
×4
742
751
690
22.7
451
454
435
6.79
0.61×
CL faster
6
200
×1
279
291
276
5.04
122
126
118
3.28
0.44×
CL faster
6
200
×4
1,052
1,086
1,046
14.7
492
500
478
8.39
0.47×
CL faster
6
CPU ×1CPU ×4
Table: light panels
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
4
×1
7.86
9.57
6.43
1.37
5.92
7.85
3.41
1.44
0.75×
CL faster
6
4
×4
14.9
15.7
14.1
0.53
10.8
11.9
10.0
0.82
0.72×
CL faster
6
20
×1
10.3
11.0
5.83
2.00
8.22
8.84
4.39
1.62
0.80×
not significant
6
20
×4
20.4
21.7
19.4
0.79
17.0
17.6
16.5
0.45
0.83×
CL faster
6
flat-20
×1
10.8
12.1
9.25
1.00
9.76
10.9
9.00
0.73
0.90×
parity
6
flat-20
×4
23.5
24.8
22.2
0.99
22.5
23.4
21.9
0.51
0.96×
parity
6
50
×1
11.0
11.9
10.4
0.57
10.6
11.6
10.1
0.53
0.96×
parity
6
50
×4
25.8
26.5
25.1
0.54
25.0
25.4
23.7
0.59
0.97×
parity
6
100
×1
15.2
15.8
13.7
0.85
15.9
17.3
15.3
0.76
1.05×
parity
6
100
×4
41.9
42.9
40.5
0.89
45.7
47.5
43.9
1.39
1.09×
parity
6
200
×1
18.8
19.7
17.9
0.70
21.2
22.2
20.1
0.82
1.13×
DV faster
6
200
×4
60.3
68.3
57.3
3.82
72.1
83.7
67.9
5.32
1.20×
DV faster
6
2Restore: new snapshot restore-replace · syncMs
Loading a snapshot of the same shape with different ids into an engine that already has a tree: both engines unmount N and mount N panels (a fair comparison after fix #1). ranked metric
CPU ×1CPU ×4
Table: heavy panels
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
4
×1
23.4
23.9
23.1
0.30
22.4
23.1
21.9
0.41
0.96×
parity
6
4
×4
92.7
94.4
91.4
1.26
86.5
87.7
84.8
1.26
0.93×
parity
6
20
×1
149
156
143
4.39
55.6
59.5
55.1
1.66
0.37×
CL faster
6
20
×4
553
570
542
10.6
241
246
224
7.76
0.44×
CL faster
6
50
×1
181
191
168
8.24
59.9
61.3
59.0
0.89
0.33×
CL faster
6
50
×4
700
721
689
12.5
245
251
228
9.14
0.35×
CL faster
6
100
×1
403
417
400
6.54
129
135
119
7.15
0.32×
CL faster
6
100
×4
1,553
1,580
1,535
15.4
505
527
471
22.7
0.32×
CL faster
6
200
×1
539
556
514
14.5
137
142
132
4.87
0.25×
CL faster
6
200
×4
2,008
2,152
1,982
77.7
556
577
545
12.6
0.28×
CL faster
6
CPU ×1CPU ×4
Table: light panels
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
4
×1
4.68
5.19
4.16
0.50
3.94
4.28
3.64
0.27
0.84×
CL faster
6
4
×4
7.95
11.2
7.22
1.39
6.85
7.21
6.22
0.37
0.86×
CL faster
6
20
×1
12.6
13.0
10.8
0.79
6.80
7.30
6.26
0.39
0.54×
CL faster
6
20
×4
28.1
30.2
27.5
0.94
15.4
16.0
14.8
0.39
0.55×
CL faster
6
50
×1
14.0
14.9
13.3
0.62
9.21
10.8
8.02
0.91
0.66×
CL faster
6
50
×4
37.5
39.0
36.5
1.05
24.6
25.3
23.8
0.51
0.65×
CL faster
6
100
×1
23.2
24.4
21.8
1.19
15.6
16.4
15.0
0.53
0.67×
CL faster
6
100
×4
82.6
86.1
78.3
2.96
47.5
49.6
46.4
1.22
0.57×
CL faster
6
200
×1
34.3
35.8
33.2
1.05
21.7
22.3
20.8
0.63
0.63×
CL faster
6
200
×4
136
156
132
8.78
79.4
88.8
78.5
4.15
0.58×
CL faster
6
3Restore: same ids restore-same-ids · syncMs
Reloading the same snapshot. CustomLayout keeps panels with the same ids and only diffs the tree (mounts = 0), while dockview fromJSON recreates everything. This is different work: the gap reflects architecture, not "speed". ranked metric
CPU ×1CPU ×4
Table: heavy panels
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
4
×1
24.3
27.1
23.2
1.41
0.43
0.48
0.39
0.03
0.02×
CL faster
6
4
×4
91.6
92.6
90.2
0.95
1.27
2.23
0.96
0.50
0.01×
CL faster
6
20
×1
145
151
141
3.85
0.81
0.96
0.68
0.13
<0.01×
CL faster
6
20
×4
557
581
548
12.4
3.24
3.55
2.49
0.41
<0.01×
CL faster
6
50
×1
185
189
181
2.52
0.93
1.00
0.87
0.05
<0.01×
CL faster
6
50
×4
699
713
675
15.6
3.51
4.11
2.91
0.41
<0.01×
CL faster
6
100
×1
397
403
389
5.68
1.67
1.88
1.62
0.10
<0.01×
CL faster
6
100
×4
1,553
1,562
1,543
7.28
7.40
109
6.81
41.5
<0.01×
CL faster
6
200
×1
521
550
501
19.5
2.51
2.64
2.35
0.11
<0.01×
CL faster
6
200
×4
2,056
2,287
1,996
114
10.9
11.6
10.1
0.65
<0.01×
CL faster
6
CPU ×1CPU ×4
Table: light panels
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
4
×1
4.66
6.32
3.75
0.85
0.93
1.52
0.63
0.32
0.20×
CL faster
6
4
×4
7.74
8.31
7.14
0.49
1.17
1.67
0.64
0.43
0.15×
CL faster
6
20
×1
13.0
14.2
11.7
0.96
1.26
1.52
1.01
0.20
0.10×
CL faster
6
20
×4
27.1
28.0
26.5
0.49
2.88
3.22
2.38
0.32
0.11×
CL faster
6
50
×1
13.8
15.9
12.7
1.21
1.50
1.65
1.34
0.12
0.11×
CL faster
6
50
×4
35.3
36.1
34.7
0.52
3.44
4.18
3.14
0.35
0.10×
CL faster
6
100
×1
23.8
26.0
20.6
1.99
2.01
2.22
1.86
0.15
0.08×
CL faster
6
100
×4
79.1
79.7
77.9
0.73
6.33
6.68
5.33
0.50
0.08×
CL faster
6
200
×1
33.2
35.9
31.6
1.58
2.52
3.28
2.44
0.32
0.08×
CL faster
6
200
×4
126
143
125
7.98
9.35
11.2
8.92
0.82
0.07×
CL faster
6
4Clearing the layout clear · syncMs
clear() / clearLayout() on a tree of N panels. ranked metric
CPU ×1CPU ×4
Table: heavy panels
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
4
×1
3.75
3.84
3.65
0.08
2.41
2.48
2.33
0.06
0.64×
CL faster
6
4
×4
14.2
15.8
13.4
1.00
9.22
10.3
8.77
0.61
0.65×
CL faster
6
20
×1
77.4
78.2
76.2
0.82
5.59
6.19
5.36
0.28
0.07×
CL faster
6
20
×4
345
383
316
24.8
23.2
24.4
22.3
0.72
0.07×
CL faster
6
50
×1
93.5
97.2
81.8
5.60
6.12
6.63
5.72
0.32
0.07×
CL faster
6
50
×4
362
403
353
19.5
23.7
26.6
23.3
1.45
0.07×
CL faster
6
100
×1
215
218
211
2.67
13.9
21.1
11.9
3.48
0.06×
CL faster
6
100
×4
874
943
866
30.6
62.4
71.1
50.1
8.09
0.07×
CL faster
6
200
×1
240
242
239
1.50
13.3
14.9
12.6
0.87
0.06×
CL faster
6
200
×4
960
1,064
947
50.1
60.0
68.6
50.1
8.27
0.06×
CL faster
6
CPU ×1CPU ×4
Table: light panels
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
4
×1
1.51
1.81
1.25
0.19
0.50
0.98
0.37
0.22
0.33×
CL faster
6
4
×4
2.98
4.29
2.47
0.67
1.11
1.33
0.94
0.17
0.37×
CL faster
6
20
×1
7.20
8.05
6.75
0.44
0.75
0.83
0.67
0.05
0.10×
CL faster
6
20
×4
17.0
19.6
14.4
1.83
2.03
2.33
1.73
0.27
0.12×
CL faster
6
50
×1
7.70
8.13
7.26
0.38
0.93
1.40
0.71
0.24
0.12×
CL faster
6
50
×4
21.0
26.3
18.4
3.25
2.61
3.69
2.27
0.53
0.12×
CL faster
6
100
×1
15.8
16.5
15.0
0.54
1.17
1.30
1.01
0.11
0.07×
CL faster
6
100
×4
50.6
64.4
46.7
6.33
3.28
4.88
3.05
0.70
0.06×
CL faster
6
200
×1
23.2
24.6
22.3
0.85
1.49
1.65
1.34
0.14
0.06×
CL faster
6
200
×4
86.2
94.5
83.4
4.46
4.85
6.80
4.21
0.99
0.06×
CL faster
6
5Removal one at a time (per operation) remove-sequential · perRemoveSyncMs
Removing a panel with a forced render after each operation: a comparable per-removal metric. ranked metric
CPU ×1CPU ×4
Table: heavy panels
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
4
×1
5.61
9.55
0.65
4.05
1.03
1.98
0.15
0.77
0.18×
not significant
24
4
×4
21.6
39.9
2.34
15.8
4.24
7.83
0.45
3.20
0.20×
not significant
24
20
×1
4.50
10.2
0.64
3.06
3.82
6.03
0.44
2.85
0.85×
not significant
120
20
×4
19.1
41.4
2.41
13.5
16.1
48.3
1.58
12.2
0.85×
not significant
120
50
×1
0.24
10.1
0.13
3.36
5.26
6.83
0.46
1.99
21.7×
DV faster
300
50
×4
1.19
40.5
0.13
13.2
21.1
27.7
1.56
8.28
17.7×
DV faster
300
100
×1
0.25
9.50
0.14
4.67
5.65
9.07
0.46
3.07
22.8×
DV faster
600
100
×4
1.16
40.2
0.14
19.1
22.3
41.3
1.78
11.5
19.1×
DV faster
600
200
×1
0.27
8.87
0.15
3.65
6.00
9.72
0.45
2.42
22.4×
DV faster
1200
200
×4
1.14
35.9
0.18
14.8
23.8
36.8
1.69
10.3
20.8×
DV faster
1200
CPU ×1CPU ×4
Table: light panels
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
4
×1
0.70
1.39
0.38
0.36
0.76
1.60
0.11
0.55
1.09×
parity
24
4
×4
1.48
3.26
0.55
0.97
1.59
4.35
0.05
1.40
1.07×
parity
24
20
×1
0.33
0.87
0.14
0.27
0.62
1.73
0.08
0.46
1.89×
not significant
120
20
×4
0.88
2.38
0.10
0.74
1.55
4.37
0.06
1.17
1.75×
not significant
120
50
×1
0.13
0.77
0.05
0.22
0.53
1.60
0.05
0.49
4.08×
DV faster
300
50
×4
0.52
2.41
0.04
0.75
1.80
5.45
0.05
1.45
3.44×
DV faster
300
100
×1
0.14
0.78
0.04
0.24
0.81
2.46
0.05
0.67
5.59×
DV faster
600
100
×4
0.61
2.78
0.03
0.91
3.25
8.50
0.05
2.48
5.28×
DV faster
600
200
×1
0.15
0.64
0.04
0.21
1.16
2.65
0.05
0.75
7.77×
DV faster
1200
200
×4
0.61
2.60
0.03
0.94
4.74
11.0
0.06
3.19
7.80×
DV faster
1200
6Removing all N in one block remove-sequential · syncMs
All N removals in a single synchronous task. dockview updates the DOM on every removePanel, CustomLayout renders once at the end: this measures the batch cost of the API, not identical work. ranked metric
CPU ×1CPU ×4
Table: heavy panels
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
4
×1
3.76
3.88
3.67
0.08
2.39
2.53
2.24
0.10
0.64×
CL faster
6
4
×4
15.6
16.1
14.4
0.68
9.73
10.4
9.46
0.32
0.63×
CL faster
6
20
×1
77.7
79.4
76.1
1.25
5.83
6.27
5.62
0.23
0.08×
CL faster
6
20
×4
325
364
320
18.1
24.7
27.1
24.2
1.12
0.08×
CL faster
6
50
×1
87.8
93.1
82.3
4.74
6.85
7.43
6.59
0.35
0.08×
CL faster
6
50
×4
361
400
343
23.5
28.2
29.4
27.1
0.85
0.08×
CL faster
6
100
×1
216
223
213
3.91
16.8
19.8
15.0
2.18
0.08×
CL faster
6
100
×4
887
982
872
50.9
78.4
89.4
62.3
10.6
0.09×
CL faster
6
200
×1
242
245
240
1.62
26.0
30.4
23.7
2.93
0.11×
CL faster
6
200
×4
971
1,048
952
42.0
115
124
95.9
10.7
0.12×
CL faster
6
CPU ×1CPU ×4
Table: light panels
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
4
×1
1.60
2.02
1.32
0.26
0.60
0.66
0.47
0.08
0.38×
CL faster
6
4
×4
3.65
4.90
3.13
0.64
1.22
1.92
0.95
0.34
0.33×
CL faster
6
20
×1
6.26
6.54
5.41
0.45
1.13
1.28
0.98
0.12
0.18×
CL faster
6
20
×4
16.5
20.1
15.1
2.03
3.14
4.02
2.87
0.41
0.19×
CL faster
6
50
×1
7.32
7.52
7.05
0.23
2.10
2.27
1.92
0.12
0.29×
CL faster
6
50
×4
22.8
28.5
20.5
3.41
6.56
7.10
6.22
0.33
0.29×
CL faster
6
100
×1
13.8
15.4
13.6
0.66
5.22
5.49
4.83
0.29
0.38×
CL faster
6
100
×4
54.4
61.9
48.5
5.68
18.3
20.1
17.8
0.84
0.34×
CL faster
6
200
×1
23.2
24.2
22.9
0.49
13.4
14.2
12.9
0.49
0.58×
CL faster
6
200
×4
91.5
98.3
89.4
3.49
51.3
56.5
50.6
2.50
0.56×
CL faster
6
7Adding a panel to the root add-k · syncMs
Adding 20 root groups to a tree of 4 (one at a time, median per addition). CustomLayout has no fine-grained API — the path is getLayout → helper → loadLayout, as in the app. ranked metric
CPU ×1CPU ×4
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
light, 4
×1
3.00
4.73
1.52
0.83
4.09
5.30
1.76
1.00
1.37×
not significant
120
light, 4
×4
4.47
7.69
2.63
1.34
7.22
10.6
3.16
2.20
1.62×
not significant
120
heavy, 4
×1
6.25
8.27
5.67
0.76
6.50
8.16
5.48
0.87
1.04×
parity
120
heavy, 4
×4
24.5
27.7
21.9
1.59
27.8
33.8
21.7
3.96
1.13×
not significant
120
8Adding a tab to a group add-k-tab · syncMs
Adding 20 tabs to an existing group (median per addition). ranked metric
CPU ×1CPU ×4
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
light, 4
×1
2.04
3.02
0.79
0.61
2.51
4.54
1.43
0.89
1.23×
not significant
120
light, 4
×4
1.66
3.29
0.60
0.72
4.80
6.80
3.13
1.01
2.88×
DV faster
120
heavy, 4
×1
7.79
8.94
5.59
0.87
8.49
9.87
5.98
1.15
1.09×
parity
120
heavy, 4
×4
23.5
27.0
21.0
1.72
27.5
31.6
22.7
2.65
1.17×
DV faster
120
9Switching a tab via the API tab-switch-api · syncMs
Programmatic tab activation in a group of 20 tabs — the main "engine cost" metric for tabs. ranked metric
CPU ×1CPU ×4
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
light, tabs-20
×1
1.51
2.20
0.42
0.46
1.60
1.88
1.12
0.22
1.05×
parity
36
light, tabs-20
×4
0.78
1.55
0.15
0.38
2.72
3.65
2.38
0.42
3.46×
DV faster
36
heavy, tabs-20
×1
6.76
7.98
5.13
0.96
5.99
6.72
4.94
0.59
0.89×
not significant
36
heavy, tabs-20
×4
18.1
19.9
16.3
0.97
18.6
25.0
17.5
1.92
1.03×
parity
36
10First tab open tab-switch-first · syncMs
First activation of each tab: for CustomLayout this is a lazy panel mount, for dockview the panel is already mounted. ranked metric
A real pointerdown → pointerup → click sequence. dockview defers activation by one rAF, so readyMs ≈ one frame. This is frame latency, not engine work. reference metric
CPU ×1CPU ×4
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
light, tabs-20
×1
17.5
19.1
15.9
0.87
1.60
1.91
1.23
0.19
0.09×
CL faster
36
light, tabs-20
×4
17.6
18.9
14.8
1.00
3.00
3.77
2.14
0.43
0.17×
CL faster
36
heavy, tabs-20
×1
24.6
26.9
15.6
2.32
6.31
6.67
5.11
0.41
0.26×
CL faster
36
heavy, tabs-20
×4
34.2
36.4
27.6
1.82
19.2
23.4
17.2
1.83
0.56×
CL faster
36
12Splitter drag: step splitter-drag · stepMs
Synthetic splitter movement: 40 steps of 6 px, synchronous processing time per step. ranked metric
CPU ×1CPU ×4
Table: heavy panels
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
4
×1
0.25
0.37
0.13
0.06
0.51
0.76
0.29
0.14
2.05×
DV faster
960
4
×4
0.23
1.07
0.09
0.34
1.27
2.28
0.25
0.50
5.58×
DV faster
960
20
×1
0.29
0.42
0.15
0.07
0.62
0.73
0.52
0.05
2.16×
DV faster
960
20
×4
0.88
1.49
0.15
0.37
2.66
3.74
1.47
0.78
3.01×
DV faster
960
50
×1
0.23
0.32
0.15
0.04
0.82
0.94
0.67
0.09
3.57×
DV faster
960
50
×4
0.94
1.63
0.14
0.38
3.37
4.29
2.24
0.50
3.57×
DV faster
960
100
×1
0.37
0.49
0.32
0.27
1.42
1.57
1.29
0.29
3.85×
DV faster
960
100
×4
2.09
2.80
0.98
0.41
6.51
7.55
5.24
0.74
3.11×
DV faster
960
200
×1
0.42
0.58
0.33
0.67
1.99
2.20
1.81
0.12
4.73×
DV faster
960
200
×4
2.39
3.08
0.67
0.43
9.51
10.8
7.77
0.93
3.97×
DV faster
960
CPU ×1CPU ×4
Table: light panels
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
4
×1
0.60
0.96
0.18
0.23
0.68
1.73
0.30
0.46
1.12×
not significant
960
4
×4
0.12
0.90
0.06
0.30
0.58
1.51
0.14
0.44
4.81×
not significant
960
20
×1
0.53
1.30
0.22
0.34
0.87
2.07
0.47
0.41
1.64×
not significant
960
20
×4
0.30
1.13
0.11
0.35
1.48
2.78
0.65
0.58
4.88×
DV faster
960
50
×1
0.37
0.53
0.26
0.08
1.09
1.68
0.87
0.30
2.99×
DV faster
960
50
×4
0.72
1.28
0.13
0.35
2.20
3.49
1.43
0.55
3.08×
DV faster
960
100
×1
0.57
0.70
0.38
0.09
1.92
2.62
1.44
0.30
3.38×
DV faster
960
100
×4
1.89
2.67
0.66
0.72
4.21
5.40
3.18
0.54
2.23×
DV faster
960
200
×1
0.58
0.72
0.38
0.07
2.59
3.24
2.02
0.29
4.42×
DV faster
960
200
×4
2.03
2.76
0.67
0.61
6.29
7.92
5.14
0.73
3.10×
DV faster
960
13Splitter drag: release splitter-drag · commitMs
Splitter release: committing sizes and the final repaint. ranked metric
Resize observer only. dockview does ResizeObserver → rAF → layout, so its readyMs includes a frame of waiting. Do not rank — read together with framesToSettle. reference metric
CPU ×1CPU ×4
Table: heavy panels
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
4
×1
22.1
24.9
20.2
1.34
0.16
0.23
0.12
0.03
<0.01×
CL faster
36
4
×4
31.8
34.6
29.8
1.34
0.52
1.04
0.09
0.40
0.02×
CL faster
36
20
×1
24.6
31.9
22.5
2.38
0.24
0.29
0.19
0.02
<0.01×
CL faster
36
20
×4
45.4
79.7
41.9
14.0
1.03
1.56
0.25
0.32
0.02×
CL faster
36
50
×1
23.6
29.1
21.7
2.21
0.25
0.37
0.21
0.04
0.01×
CL faster
36
50
×4
58.4
88.9
37.4
17.1
1.25
1.77
0.60
0.33
0.02×
CL faster
36
100
×1
31.4
33.7
22.2
2.84
0.45
0.55
0.36
0.05
0.01×
CL faster
36
100
×4
99.0
151
83.0
21.5
2.13
2.65
1.23
0.37
0.02×
CL faster
36
200
×1
30.4
35.6
22.6
3.78
0.47
0.59
0.36
0.06
0.02×
CL faster
36
200
×4
111
153
91.0
21.6
1.90
2.88
1.07
0.46
0.02×
CL faster
36
CPU ×1CPU ×4
Table: light panels
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
4
×1
18.7
20.8
15.5
1.37
0.32
0.90
0.15
0.23
0.02×
CL faster
36
4
×4
18.1
19.6
16.6
0.81
0.28
0.99
0.08
0.32
0.02×
CL faster
36
20
×1
18.3
20.5
16.1
1.15
0.40
1.00
0.32
0.22
0.02×
CL faster
36
20
×4
19.6
21.4
17.9
0.88
0.94
1.35
0.16
0.35
0.05×
CL faster
36
50
×1
18.7
19.8
16.8
0.95
0.44
0.58
0.30
0.07
0.02×
CL faster
36
50
×4
20.0
22.4
12.0
1.65
0.89
1.45
0.21
0.28
0.04×
CL faster
36
100
×1
19.4
20.8
17.7
0.84
0.75
0.94
0.58
0.10
0.04×
CL faster
36
100
×4
20.6
23.9
17.9
1.77
1.77
2.36
1.11
0.33
0.09×
CL faster
36
200
×1
19.8
21.3
17.1
1.02
0.71
0.88
0.55
0.10
0.04×
CL faster
36
200
×4
25.4
41.4
17.5
4.55
1.83
2.41
1.06
0.38
0.07×
CL faster
36
18Moving a panel between groups move · syncMs
Moving a panel to another group. In CustomLayout: getLayout → moveItemToStack → loadLayout. ranked metric
CPU ×1CPU ×4
Table: heavy panels
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
20
×1
9.78
10.6
8.81
0.54
9.64
10.5
8.88
0.48
0.99×
parity
36
20
×4
37.9
40.8
34.1
1.71
37.9
42.2
35.6
3.52
1.00×
parity
36
50
×1
10.1
10.7
9.02
0.49
10.9
12.2
9.88
0.58
1.09×
parity
36
50
×4
38.6
41.9
35.5
4.66
42.3
62.6
39.3
6.58
1.09×
parity
36
100
×1
10.1
10.6
9.74
0.24
11.8
12.4
11.1
0.34
1.17×
DV faster
36
100
×4
40.9
43.9
38.7
1.47
46.0
73.6
42.6
7.45
1.12×
DV faster
36
200
×1
10.2
10.7
9.78
0.22
12.6
13.4
11.6
0.50
1.23×
DV faster
36
200
×4
40.5
43.3
38.4
1.29
49.9
52.4
45.1
1.56
1.23×
DV faster
36
CPU ×1CPU ×4
Table: light panels
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
20
×1
2.03
3.24
0.99
0.69
2.53
3.03
2.03
0.30
1.25×
not significant
36
20
×4
2.07
3.08
1.01
0.45
5.37
6.93
3.90
1.08
2.59×
DV faster
36
50
×1
1.60
3.30
1.10
0.71
3.47
3.98
2.67
0.36
2.18×
DV faster
36
50
×4
2.78
3.61
1.86
0.52
7.65
9.35
6.13
0.76
2.75×
DV faster
36
100
×1
1.23
1.50
0.89
0.25
4.79
5.92
3.64
0.57
3.88×
DV faster
36
100
×4
3.10
3.99
2.18
0.44
10.6
11.8
9.10
0.89
3.42×
DV faster
36
200
×1
1.34
1.94
1.09
0.28
5.74
6.77
4.50
0.68
4.27×
DV faster
36
200
×4
3.75
4.86
2.36
0.53
14.6
15.7
12.6
0.75
3.90×
DV faster
36
19Serialization serialize · serializeUs
toJSON() / getLayout(), microseconds per call (300 calls per measurement). getLayout makes a deep copy. ranked metric
Same, plus JSON.stringify of the result. reference metric
CPU ×1CPU ×4
Table: heavy panels
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
4
×1
1.98
2.72
1.53
0.28
8.95
9.63
7.90
0.51
4.51×
DV faster
36
4
×4
5.90
7.52
3.57
1.04
27.5
29.3
24.3
1.19
4.66×
DV faster
36
20
×1
9.48
10.8
8.70
0.62
19.9
20.4
18.9
0.44
2.10×
DV faster
36
20
×4
33.8
39.2
31.0
2.19
78.8
83.3
75.2
2.09
2.33×
DV faster
36
50
×1
16.1
23.8
15.2
3.15
36.5
37.9
35.1
0.62
2.27×
DV faster
36
50
×4
65.5
96.6
60.3
10.5
141
152
137
4.00
2.15×
DV faster
36
100
×1
31.7
33.7
30.8
0.94
72.9
74.7
71.0
1.10
2.30×
DV faster
36
100
×4
128
136
123
4.03
283
306
274
9.73
2.21×
DV faster
36
200
×1
56.9
59.5
55.6
0.82
125
127
123
3.57
2.20×
DV faster
36
200
×4
226
233
216
3.91
499
524
474
16.3
2.21×
DV faster
36
CPU ×1CPU ×4
Table: light panels
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
4
×1
2.47
6.95
1.52
1.40
10.4
12.2
6.88
2.00
4.20×
DV faster
36
4
×4
6.25
8.03
3.43
1.27
27.4
28.5
25.5
1.04
4.38×
DV faster
36
20
×1
13.2
15.6
11.3
1.11
20.7
24.2
19.2
1.46
1.57×
DV faster
36
20
×4
33.9
37.7
32.0
1.53
78.2
84.1
74.9
2.53
2.31×
DV faster
36
50
×1
19.6
21.6
18.7
0.85
36.8
38.8
35.7
0.88
1.88×
DV faster
36
50
×4
63.7
69.4
59.9
3.05
145
151
139
3.16
2.28×
DV faster
36
100
×1
31.4
35.6
30.5
1.48
73.4
75.1
71.9
0.83
2.33×
DV faster
36
100
×4
126
136
120
4.00
288
300
276
6.48
2.28×
DV faster
36
200
×1
57.0
60.1
55.6
1.39
126
127
123
1.10
2.20×
DV faster
36
200
×4
227
236
219
7.19
496
521
484
11.1
2.18×
DV faster
36
21Mount/unmount cycles mount-cycles · cycleMs
8 cycles of "mount 50 panels → unmount the whole engine", two rounds per pass with alternating engine order. ranked metric
CPU ×1CPU ×4
Size
CPU
dockview
CustomLayout
CL / DV
Verdict
n
median
p95
min
σ
median
p95
min
σ
light, 50
×1
133
137
118
4.64
133
137
118
4.08
1.00×
parity
48
light, 50
×4
150
154
140
3.04
135
150
128
6.76
0.90×
parity
48
heavy, 50
×1
252
270
219
13.7
169
188
161
7.66
0.67×
CL faster
48
heavy, 50
×4
686
712
640
17.8
419
440
399
14.6
0.61×
CL faster
48
05Scaling
Median by panel count (4, 20, 50, 100, 200; sizes with tabs in groups, see the size table). Two charts per operation: CPU ×1 and ×4. Panel type follows the toggle above (currently: heavylight).
Cold mountRestore (new ids)CleanupRemoval, per operationSplitter stepSerialization
Cold mountRestore (new ids)CleanupRemoval, per operationSplitter stepSerialization
How many panels are actually mounted
alivePanels after cold mount: dockview / CustomLayout. This explains why the CustomLayout curves grow more slowly: it mounts only active tabs.
Panels
4
20
flat-20
50
100
200
tabs-20
heavy
4 / 4
20 / 10
20 / 20
50 / 10
100 / 20
200 / 20
21 / 2
light
4 / 4
20 / 10
20 / 20
50 / 10
100 / 20
200 / 20
21 / 2
06Memory and leaks
Neither engine shows DOM leaks: after 8 mount/unmount cycles of 50 panels there are 0 live panels, and growth in document nodes and body children is 0. Heap: for dockview after a forced GC the median growth is +2.4 MB (light) and +15.4–30.8 MB (heavy, ×4 and ×1), but the spread is large (heavy at ×4 ranges from 0.2 to 15.9 MB). A slope of ~15–25 KB per cycle adds only ~0.1–0.2 MB over 8 cycles, so the growth is more likely one-off retention (caches/closures) than a linear leak. For CustomLayout the median growth is negative (−0.6…−6.2 MB), but for heavy panels the range reaches +3.7 MB, and the slope at ×4 is unstable (median +943 KB/cycle, spread from −7 KB to +1.9 MB/cycle). With 8 cycles and 6 measurements nothing can be definitively called a leak — a long run (20+ cycles) is needed. CDP usedSize before/after depends heavily on garbage left by the previous scenario (passes 1 and 3 start with a large heap), so do not use it to compare engines.
Panels
CPU
Metric
dockview, median [min … max]
CustomLayout, median [min … max]
light
×1
Heap growth after 8 cycles
2.4 MB [783.6 KB … 2.4 MB]
-937.2 KB [-2.0 MB … 21.9 KB]
light
×1
Heap slope per cycle
24.0 KB [4.8 KB … 26.2 KB]
857 B [584 B … 1.1 KB]
light
×1
Live panels after unmount
0 [0 … 0]
0 [0 … 0]
light
×1
Δ document nodes
0 [0 … 0]
0 [0 … 0]
light
×1
Δ body children
0 [0 … 0]
0 [0 … 0]
light
×1
Cycle time
133 [118 … 139]
133 [118 … 137]
light
×4
Heap growth after 8 cycles
2.4 MB [1.3 MB … 2.4 MB]
-649.0 KB [-1.5 MB … 22.0 KB]
light
×4
Heap slope per cycle
24.5 KB [4.9 KB … 25.1 KB]
601 B [-4.8 KB … 1.2 KB]
light
×4
Live panels after unmount
0 [0 … 0]
0 [0 … 0]
light
×4
Δ document nodes
0 [0 … 0]
0 [0 … 0]
light
×4
Δ body children
0 [0 … 0]
0 [0 … 0]
light
×4
Cycle time
150 [140 … 156]
135 [128 … 151]
heavy
×1
Heap growth after 8 cycles
30.8 MB [16.0 MB … 31.7 MB]
-6.2 MB [-16.1 MB … 3.7 MB]
heavy
×1
Heap slope per cycle
14.9 KB [-7.7 KB … 50.7 KB]
-3.3 KB [-1.9 MB … 1.9 MB]
heavy
×1
Live panels after unmount
0 [0 … 0]
0 [0 … 0]
heavy
×1
Δ document nodes
0 [0 … 0]
0 [0 … 0]
heavy
×1
Δ body children
0 [0 … 0]
0 [0 … 0]
heavy
×1
Cycle time
252 [219 … 272]
169 [161 … 191]
heavy
×4
Heap growth after 8 cycles
15.4 MB [208.5 KB … 15.9 MB]
-6.2 MB [-16.1 MB … 3.7 MB]
heavy
×4
Heap slope per cycle
15.1 KB [3.7 KB … 37.1 KB]
943.2 KB [-7.3 KB … 1.9 MB]
heavy
×4
Live panels after unmount
0 [0 … 0]
0 [0 … 0]
heavy
×4
Δ document nodes
0 [0 … 0]
0 [0 … 0]
heavy
×4
Δ body children
0 [0 … 0]
0 [0 … 0]
heavy
×4
Cycle time
686 [640 … 732]
419 [399 … 474]
CDP Runtime.getHeapUsage around mount-cycles (per engine)
Pass
CPU
dockview Δ usedSize
CustomLayout Δ usedSize
Order
1
×1
-48.2 MB
-15.9 MB
dockview → custom
2
×1
16.0 MB
-2.2 MB
custom → dockview
3
×1
-48.2 MB
-16.0 MB
dockview → custom
1
×4
-2.2 MB
27.5 KB
dockview → custom
2
×4
42.3 KB
-2.2 MB
custom → dockview
3
×4
-2.2 MB
42.4 KB
dockview → custom
07DOM nodes
Counted after mount, CPU ×1, dockview / CustomLayout. "Chrome" means engine nodes excluding panel content (splitters, headers, tabs). Panel type follows the toggle.
"chrome" nodes (excluding panel content)
"chrome" nodes (excluding panel content)
Size
live panels
visible
detached
nodes in scene
panel nodes
"chrome" nodes
off-scene nodes
4
4 / 4
4 / 4
0 / 0
5,719 / 5,724
5,612 / 5,612
107 / 112
0 / 0
20
20 / 10
10 / 10
10 / 0
14,321 / 14,406
14,030 / 14,030
291 / 376
0 / 0
flat-20
20 / 20
20 / 20
0 / 0
28,521 / 28,614
28,060 / 28,060
461 / 554
0 / 0
50
50 / 10
10 / 10
40 / 0
14,511 / 14,716
14,030 / 14,030
481 / 686
0 / 0
100
100 / 20
20 / 20
80 / 0
29,101 / 29,440
28,060 / 28,060
1,041 / 1,380
0 / 0
200
200 / 20
20 / 20
180 / 0
29,701 / 30,440
28,060 / 28,060
1,641 / 2,380
0 / 0
tabs-20
21 / 2
2 / 2
19 / 0
2,984 / 3,053
2,806 / 2,806
178 / 247
0 / 0
4
4 / 4
4 / 4
0 / 0
119 / 124
12 / 12
107 / 112
0 / 0
20
20 / 10
10 / 10
10 / 0
321 / 406
30 / 30
291 / 376
0 / 0
flat-20
20 / 20
20 / 20
0 / 0
521 / 614
60 / 60
461 / 554
0 / 0
50
50 / 10
10 / 10
40 / 0
511 / 716
30 / 30
481 / 686
0 / 0
100
100 / 20
20 / 20
80 / 0
1,101 / 1,440
60 / 60
1,041 / 1,380
0 / 0
200
200 / 20
20 / 20
180 / 0
1,701 / 2,440
60 / 60
1,641 / 2,380
0 / 0
tabs-20
21 / 2
2 / 2
19 / 0
184 / 253
6 / 6
178 / 247
0 / 0
08Bundle size
In the app build both engines are bundled into the main index chunk, so sizes are taken from separate library builds of each engine (vite, same minification config).
JS and CSS, gzip / brotli compression
dockview
CustomLayout
DV / CL
JS raw
361.5 KB
42.5 KB
8.5×
JS gzip
86.3 KB
14.2 KB
6.1×
JS brotli
72.0 KB
12.7 KB
5.7×
CSS gzip
11.0 KB
4.4 KB
2.5×
CSS brotli
9.2 KB
3.9 KB
2.4×
Source modules
dockview-core 700.6 KB, dockview-vue 18.4 KB
custom-layout 90.2 KB
App index chunk
2.440.8 KB raw / 730.6 KB gzip (both engines inside)
Against the ~731 KB gzip main chunk, the difference of ~79 KB is about 11% of the bundle.
09Features: speed isn't everything
dockview is a mature library with a broad API; CustomLayout (~3.7k lines of TS/Vue and ~0.8k lines of SCSS themes in src/components/custom-layout) covers what the terminal needs today, but everything else would have to be written and maintained in-house.
Capability
dockview 8.4
CustomLayout
Nested row/column splits
yes
yes (MAX_TREE_DEPTH, config validation)
Tabbed groups
yes
yes (stacks)
Tab DnD between groups and to edges
yes, customizable overlays and zones
yes: group zones and root edges
Dragging a whole group
yes
yes
Touch dragging
limited — relies on HTML5 DnD
yes, custom use-touch-drag
Floating groups
yes (now persisted in the workspace)
no
Popout to a separate window
yes
no
Maximize group
yes (maximize)
yes (stack fullscreen)
Tab overflow
yes (dropdown list)
yes ("+N" menu, menu item slot)
Lazy mounting of hidden tabs
no — a component is created for every panel (alivePanels = N)
yes — only tabs that have ever been visible
Fine-grained API (activate, move, addPanel to a group, sizes)
yes, plus dozens of events (onDidActivePanelChange, onDidLayoutChange, onWillDrop…)
minimal: add/remove/load/get/clear; activation and moving go through a full config reload
Serialization
toJSON — ~11 µs at 200 panels
getLayout — deep copy, ~115 µs
Minimum sizes
in pixels (group no smaller than 100 px)
in percent (no less than 5%); groups keep shrinking
Accessibility
partial: aria-live announcements (disabled in the app), limited keyboard navigation
external dependency; the 5.2 → 8.4 upgrade required fixes and surfaced a blocker
own code — full control, all maintenance and testing on the team
Size (JS gzip)
86.3 KB
14.2 KB
10dockview 5.2 → 8.4 upgrade
Changes
dockview-vue 5.2.0 → 8.4.0, plus an explicit dependency dockview 8.4.0; dockview-core is no longer imported directly.
Style import moved to dockview-vue/dist/styles/dockview.css.
Payload onDidActivePanelChange is now { panel, origin }.
The component root became a fragment — the layout's scoped styles were moved to :deep().
floating-group-drag-handle="tabbar" — to keep the 5.x look.
Light theme: color-scheme: light and --dv-floating-border.
Floating groups are now persisted (dockviewToGl / glToDockview — floatingGroups).
.dv-shell got isolation: isolate.
New spec dockview-integration.spec.ts (8 tests).
Blocker found in the browser smoke test
Vue casts an omitted Boolean prop to false. As a result, proportionalLayout became false, and core 8.4 produced NaN sizes for nested splits; the same cast disabled the root edge drop zones. Fixed with explicit props:
Also, panels are mounted via Teleport one tick after addPanel/fromJSON — the benchmark waits for nextTick + requestAnimationFrame before stopping the timers.
Checks
Unit tests 229/229 after the upgrade (271/271 after adding the benchmark); the build passes.
Typecheck: 99 errors, all pre-existing, no new ones.
Smoke: /dockview-demo 18/18; /trading-dockview 8/10 — 2 long-standing issues (a closed tab is not hidden in the spec after reload; report table console errors caused by the mock).
Known and not fixed: glToDockview ignores missing and percentage sizes.
11How to rerun
In the browser
VITE_LAYOUT_BENCH=1 npm run build
npx vite preview --port 5050
# open http://localhost:5050/layout-benchmark
The /layout-benchmark route is available only in a build with VITE_LAYOUT_BENCH=1. The page offers selection of scenarios, sizes and engines, progress, and a results table with JSON export. From the console:
Important: after the run, rebuild without the flag — dist/ currently contains a build with the benchmark route.
Full run via Playwright
Script: perf-reports/layout-benchmark/run.mjs (the runner for this run). It builds the project, measures bundle size, starts preview on :5050, mocks all /api/* (non-GET requests are blocked), runs passes with CDP throttling and real drag, and writes results.json next to itself.
Next to the script are mocks.mjs (mocks for /api/*) and size/ (a separate engine build for bundle measurement). Playwright is not a project dependency: install it in any folder (npm i playwright) and pass the path via PLAYWRIGHT_DIR. The defaults (10/30 iterations, 20 cycles) take ~5 h; this report was produced with reduced values via --config (the command is in the header of run.mjs).
12Raw data
The page embeds JSON (<script type="application/json" id="bench-results">): meta, env, bundle, safety, all 2344 aggregates, comparisons, the re-check, and pass summaries (CDP heap, trusted drag without per-sample arrays). Per-sample data (the full results.json, 13 MB) is not embedded due to its size.