Skip to content
HELiX

Performance Benchmarks

apps/docs/src/content/docs/components/performance/benchmarks Click to copy
Copied! apps/docs/src/content/docs/components/performance/benchmarks

Real, measured performance data for HELiX. Updated on each release using automated tooling in CI.

HELiX enforces two distinct bundle-size targets:

  • CI ceiling (enforced): 16 KB gzipped per component, 200 KB gzipped total — read from bundle-budgets.json and gated by scripts/bundle-size-report.js --ci. Exceeding the ceiling fails the PR.
  • Aspirational floor (regression flag): <5 KB gzipped per component / <50 KB gzipped total — read from .bundle-budget.json. Going over the floor surfaces a regression flag but does not block the merge.

Sizes are measured by bundling each component individually with esbuild, externalizing lit, @helixui/tokens, @helixui/icons, and @floating-ui. The “Full library” total in the table below is the sum of those independently bundled per-component outputs — it is not a single deduplicated bundle of all components. That number reflects worst-case “import every component separately” rather than what a real consumer ships.

The table below is a historical snapshot from an earlier release. Run node scripts/bundle-size-report.js --markdown against the current main to regenerate it; the values, the “72 components” count, and the over-budget list below all change with the source.

The shipped library currently exposes 81 component directories that register 102 custom elements (packages/hx-library/custom-elements.json is authoritative). Re-render this section against the live report before relying on the numbers.

Measured with node scripts/bundle-size-report.js (tree-shaken, minified, gzipped):

ComponentRawGzippedBudget
hx-accordion8.05 KB2.79 KBPass
hx-action-bar6.78 KB2.33 KBPass
hx-alert10.69 KB3.23 KBPass
hx-avatar6.53 KB2.34 KBPass
hx-badge7.35 KB2.21 KBPass
hx-breadcrumb8.36 KB2.80 KBPass
hx-button8.17 KB2.38 KBPass
hx-button-group4.05 KB1.16 KBPass
hx-card7.41 KB2.17 KBPass
hx-carousel17.71 KB4.39 KBPass
hx-checkbox12.40 KB3.40 KBPass
hx-checkbox-group6.70 KB2.15 KBPass
hx-code-snippet9.39 KB2.72 KBPass
hx-color-picker22.58 KB5.60 KBOver
hx-combobox24.15 KB5.82 KBOver
hx-container2.78 KB0.93 KBPass
hx-copy-button6.08 KB2.16 KBPass
hx-data-table12.13 KB3.73 KBPass
hx-date-picker26.58 KB6.29 KBOver
hx-dialog11.34 KB3.42 KBPass
hx-divider3.85 KB1.42 KBPass
hx-drawer13.87 KB3.82 KBPass
hx-dropdown6.34 KB2.31 KBPass
hx-field8.68 KB2.62 KBPass
hx-field-label2.33 KB1.01 KBPass
hx-file-upload14.95 KB4.27 KBPass
hx-form5.64 KB1.98 KBPass
hx-format-date4.26 KB1.66 KBPass
hx-grid2.72 KB1.08 KBPass
hx-help-text3.55 KB1.30 KBPass
hx-icon5.31 KB2.06 KBPass
hx-image4.70 KB1.62 KBPass
hx-link4.83 KB1.77 KBPass
hx-list10.29 KB2.82 KBPass
hx-menu10.93 KB3.37 KBPass
hx-meter4.88 KB1.79 KBPass
hx-nav12.81 KB3.51 KBPass
hx-number-input16.58 KB4.19 KBPass
hx-overflow-menu8.22 KB2.75 KBPass
hx-pagination12.28 KB3.17 KBPass
hx-popover7.04 KB2.41 KBPass
hx-popup5.57 KB2.00 KBPass
hx-progress-bar6.09 KB2.02 KBPass
hx-progress-ring6.67 KB2.08 KBPass
hx-prose2.11 KB0.96 KBPass
hx-radio-group12.27 KB3.50 KBPass
hx-rating8.57 KB2.67 KBPass
hx-select20.72 KB5.18 KBOver
hx-side-nav15.29 KB3.92 KBPass
hx-skeleton3.50 KB1.34 KBPass
hx-slider14.90 KB4.03 KBPass
hx-spinner4.85 KB1.82 KBPass
hx-split-button15.13 KB3.47 KBPass
hx-split-panel8.80 KB2.57 KBPass
hx-stack2.99 KB0.95 KBPass
hx-status-indicator3.52 KB1.21 KBPass
hx-steps12.75 KB3.09 KBPass
hx-structured-list3.43 KB1.14 KBPass
hx-switch9.47 KB2.72 KBPass
hx-tabs12.68 KB3.61 KBPass
hx-tag6.82 KB2.23 KBPass
hx-text5.77 KB1.48 KBPass
hx-text-input11.70 KB3.11 KBPass
hx-textarea10.47 KB2.86 KBPass
hx-theme4.55 KB1.76 KBPass
hx-time-picker18.79 KB5.13 KBOver
hx-toast9.53 KB2.92 KBPass
hx-toggle-button8.87 KB2.37 KBPass
hx-tooltip5.63 KB2.11 KBPass
hx-top-nav8.33 KB2.61 KBPass
hx-tree-view10.90 KB3.21 KBPass
hx-visually-hidden1.31 KB0.63 KBPass
Total (72 components)655.26 KB191.59 KBPass
  • Smallest: hx-visually-hidden (0.63 KB gzipped)
  • Largest: hx-date-picker (6.29 KB gzipped)
  • Median: ~2.4 KB gzipped
  • 67 of 72 components are under the 5 KB budget

Against the aspirational 5 KB floor, a handful of complex widgets historically exceeded it — calendar rendering, color space conversion, and typeahead logic carry weight that’s hard to compress further. Against the CI-enforced 16 KB ceiling, zero shipping components are currently over budget; node scripts/bundle-size-report.js --ci exits non-zero only when a component blows the ceiling, not when it merely crosses the floor.

To see the current over-floor list against your local source:

Terminal window
node scripts/bundle-size-report.js --markdown | grep -E "Over|over"

Optimization work for components that hover above the floor is tracked in the project backlog.

Lighthouse Scores (manual, not a CI artifact)

Section titled “Lighthouse Scores (manual, not a CI artifact)”

There is no Lighthouse CI workflow wired into the repo at the moment — these numbers come from manual, dated Lighthouse runs against the production documentation site (helix.bookedsolid.tech) and should be retaken before relying on them. The table is illustrative of the target band, not a continuously regenerated artifact:

MetricScore (latest manual)Target
Performance95+90
Accessibility100100
Best Practices10095
SEO10090

The docs site uses Astro Starlight’s static-generation output. It is not a zero-JS surface — Astro injects an inline browser script for view transitions, and Starlight ships small interactive components (search input, theme/version toggles, sidebar collapse). The hydrated JS footprint is intentionally minimal, but “zero client-side JavaScript” overstates it; we’d describe it as static-first with a thin interactive surface.

MetricValueThreshold
Largest Contentful Paint (LCP)< 2.5s< 2.5s
Interaction to Next Paint (INP)< 200ms< 200ms
Cumulative Layout Shift (CLS)< 0.1< 0.1
Terminal window
# Human-readable table
node scripts/bundle-size-report.js
# JSON output (for tooling integration)
node scripts/bundle-size-report.js --json
# Markdown table (for documentation updates)
node scripts/bundle-size-report.js --markdown
# CI mode (exits non-zero on budget violations)
node scripts/bundle-size-report.js --ci
Terminal window
# Install Lighthouse CI
npm install -g @lhci/cli
# Run against production site
lhci autorun --collect.url=https://helix.bookedsolid.tech
# Run against local dev server
lhci autorun --collect.url=http://localhost:3150

Bundle sizes are checked on every pull request:

  1. Per-component CI ceiling: Each component is individually tree-shaken and measured. The configured ceiling is 16 KB gzipped per component (bundle-budgets.json). Exceeding the ceiling fails the PR.
  2. Per-component floor: A separate 5 KB aspirational floor (.bundle-budget.json) surfaces a regression flag without blocking — useful for catching gradual growth.
  3. Full-library total: bundle-size-report --ci currently exits non-zero only on per-component ceiling violations; the 200 KB total is reported but not (yet) wired as a hard failure condition. Track that gap as a follow-up if you need a total-failure gate.

See .github/workflows/ci.yml for the full configuration.

LibraryButton Size (gz)Full Bundle (gz)Tree-Shakeable
HELiXregenerate from bundle-size-reportregenerate from bundle-size-reportYes
shadcn/ui~3-5 KBN/A (copy-paste)Partial
Radix Primitives~2-4 KB~150-200 KBYes
Material Web~5-8 KB~300+ KBYes

Note: Comparisons are approximate and the third-party numbers are uncited estimates — treat them as a directional sanity check, not a benchmark. HELiX externalizes Lit (~16 KB gzipped), which consumers typically already have in their dependency tree. shadcn/ui externalizes React (~40 KB gzipped). Run bundle-size-report --markdown to fill in the live HELiX row before publishing.

Bundle sizes are measured using the following methodology:

  1. Tool: esbuild with tree-shaking and minification enabled
  2. Externals: lit, @lit/*, @helixui/tokens, @floating-ui/* are externalized (not counted)
  3. Format: ES modules
  4. Compression: gzip (standard level)
  5. Measurement: Each component is bundled independently from its source entry point
  6. Automation: scripts/bundle-size-report.js generates all data programmatically