JavaScript chart libraries are powerful, and heavy. For many pages you only need a trend, a bar comparison, or a simple gauge. Shipping 40-150 KB of chart runtime (plus hydration) is optional, not inevitable.
Three open approaches solve "show the data" without a client chart engine. They are not drop-in replacements for each other. They target different workflows.
The shared idea
All three keep visualization close to the browser's normal layout and paint path:
- less main-thread chart code on first load
- markup or CSS that crawlers and simple clients can see without executing a chart bundle
- a clearer story for Core Web Vitals on content and marketing surfaces
How you author the chart is where they diverge.
Charts.css: tables first
Charts.css styles semantic HTML <table> markup. Classes and CSS variables turn rows and cells into bars, lines, and related views.
Best when
- Accessibility is non-negotiable (e.g. WCAG-minded reports): the underlying table remains real data for screen readers
- Marketing pages, blogs, CMS content, public reports
- Static sites (Astro, Eleventy, Jekyll) where the chart is content, not an app shell
Workflow: write or generate a table, apply Charts.css classes, tune with CSS variables.
If your source of truth is already tabular and you care about semantics first, this is the natural fit.
ProvChart: data in, markup out
ProvChart treats charts as compile output: JSON (or a builder) becomes scoped HTML + CSS, or SVG for README/docs. Paint does not require a chart-library runtime. An optional small runtime can add tooltips later; the chart should still be visible without it.
Best when
- Performance-sensitive pages (SSR, Jamstack widgets, mobile / low bandwidth)
- Backend or CI owns the numbers; the page only injects markup
- E-commerce or product surfaces where third-party chart scripts are a risk on the path to purchase
- Agents/CI: API or MCP generates HTML/CSS or SVG from metrics
Workflow: metrics go to API or builder, then inject css + html (or commit .svg).
If your source of truth is JSON from a server or pipeline, and first paint matters more than an interactive analytics canvas, this fits.
FSCSS / st-core: charts as a CSS design layer
st-core.fscss lives in the FSCSS world: you describe chart structure in .fscss, and it compiles toward native CSS (custom properties, clip-path, grids, etc.).
Best when
- Design systems and shared UI kits across React, Vue, Svelte, or plain HTML
- Utility-first teams that want axes, fills, and grids as layout primitives
- Fine control over geometry in CSS (including modern layout features) without a canvas API
Workflow: author in FSCSS, compile, ship CSS (+ light markup), same as the rest of the design system.
If charts are components in a design language, not one-off API responses, st-core is aimed at you.
Side-by-side
| Focus | Charts.css | ProvChart | FSCSS (st-core) |
|---|---|---|---|
| Data enters as | HTML <table>
|
JSON / API properties |
.fscss + CSS utilities |
| Strength | Accessibility & readable structure | Load speed & zero chart hydration | Custom visual systems |
| Feels like | Content + CSS framework | Compile step / service | Design-token / compiler layer |
How to choose
- Report or article with real tables -> Charts.css
- Product page or dashboard strip fed by an API -> ProvChart
- Multi-app design system, CSS-first components -> st-core / FSCSS
Many orgs use more than one: tables in the docs site, compiled API charts in the app header, st-core tokens in the component library.
What none of these replace
Brushing, crossfiltering, streaming ticks, and deep drill-down still favor a dedicated JS (or WebGL) library, on the routes that earn that cost. The win is defaulting content and KPI chrome to CSS-native pipelines so the heavy toolkit stays optional.
Links
Pick the workflow that matches how your data already lives, table, JSON, or design system, not the logo with the longest feature list.
Top comments (0)