No JS. No SVG. No canvas. Just CSS — and one import.
Here's what that actually looks like in practice.
The problem with dashboard UIs
Every time I need a stats dashboard — chart, bars, stat cards, the whole thing — I end up writing the same boilerplate. CSS variables, clip-path polygons, card layouts. It's not hard, but it's repetitive. And when you're working across multiple projects, copy-pasting that foundation every time gets old fast.
So packaged it.
st-core.fscss is an open source plugin for FSCSS that gives you a complete trading/stats dashboard design system in a single import. MIT licensed, no dependencies besides the FSCSS runtime or cli.
What you get
A full set of @st-* mixins that each generate a production-ready component:
| Mixin | Output |
|---|---|
@st-root() |
Design tokens (colors, radius, spacing) on :root
|
@st-stat-card |
Stat card — label, value, up/down delta |
@st-chart-fill |
Gradient area fill under a chart line |
@st-chart-line |
Glowing line stroke |
@st-chart-dot |
Positioned data point with tooltip support |
@st-chart-grid |
Background grid lines |
@st-chart-axis-x/y |
Axis label rows |
@st-chart-points |
Inject 8 data values into a chart |
@st-cat-bar-fill |
Gradient progress bar fill |
@st-phone |
Mock phone/device frame |
How the chart works — pure CSS, no JS
This is the interesting part. The chart is a clip-path: polygon() shape.
You pass 8 Y values to @st-chart-points, which writes them as CSS custom properties — --st-p1 through --st-p8 — on your chart container. The fill and line elements inside read those values and clip themselves accordingly.
.chart {
position: relative;
height: 200px;
overflow: hidden;
background: var(--st-surface);
/* your 8 data points */
@st-chart-points(20, 35, 33, 30, 48, 35, 66, 37)
}
That's it. No JS. No SVG path calculations. The "line" is a thin filled polygon with two rows of points — the front edge and the back edge — separated by --st-chart-line-width. Change the width, the line redraws.
.chart-line {
@st-chart-line-width(2px)
}
A minimal full example
demo using runtime
<script src="https://cdn.jsdelivr.net/npm/fscss@1.1.24/exec.min.js" async></script>
<style>
@import((*) from st-core)
/* ================= INIT ================= */
@st-root()
@st-container(body)
/* ================= COMPONENTS ================= */
@st-chart-fill(.chart-fill)
@st-chart-line(.chart-line)
@st-chart-dot(.chart-dot, 70, 60)
/* ================= CHART ================= */
.chart{
width: 100%;
height: 200px;
border-radius: 25px;
position: relative;
overflow: hidden;
background: var(--st-surface);
/* DATA (main power) */
@st-chart-points(20,25,21,37,30,60,27,50)
}
@st-phone(.wrapper)
/* ================= LINE ================= */
.chart-line{
/* controlled via helper */
@st-chart-line-width(2px);
/* optional override */
filter: drop-shadow(0 0 8px var(--st-accent));
}
/* ================= FILL ================= */
.chart-fill{
/* enhance fill visibility */
opacity: .85;
}
/* ================= DOT ================= */
.chart-dot{
position: relative;
overflow: visible;
/* local customization */
--st-accent: #c4a8ff; /* overrides root accent just for dot */
}
/* tooltip */
.chart-dot:after{
content: attr(data-point);
background: var(--st-accent);
padding: 6px 8px;
font-size: 12px;
font-weight: 700;
color: #fff;
border-radius: var(--st-radius-sm);
position: absolute;
top: -40px;
left: -22px;
white-space: nowrap;
}
/* arrow */
.chart-dot:before{
content: '';
width: 10px;
height: 10px;
background: var(--st-accent);
transform: rotate(45deg);
position: absolute;
top: -18px;
left: 2px;
}
/* ================= EXTRA (USING st-core IDEA) ================= */
@st-stat-card(.stat-card)
@st-chart-axis-x(.x-axis)
@st-chart-axis-y(.y-axis)
@st-chart-grid(.chart-grid, 10, 7)
</style>
<div class="wrapper">
<div class="stat-card">
<div class="st-stat-label">TOTAL EXPENSES</div>
<div class="st-stat-value">$1,326.03</div>
<div class="st-stat-delta up">+5.1% vs last week</div>
</div>
<div class="chart">
<div class="chart-fill"></div>
<div class="chart-line"></div>
<div class="chart-dot" data-point="$405.67"></div>
<div class="chart-grid"></div>
<div class="y-axis">
<span>0</span>
<span>10</span>
<span>20</span>
<span>30</span>
<span>40</span>
<span>50</span>
<span>60</span>
<span>70</span>
<span>80</span>
<span>90</span>
<span>100</span>
</div>
</div>
<div class="x-axis days">
<span>Sun</span>
<span>Mon</span>
<span>Tue</span>
<span>Wed</span>
<span>Thu</span>
<span>Fri</span>
<span>Sat</span>
<span>Sun</span>
</div>
</div>
A full chart with a stat card and axis labels. That's the entire CSS. No custom polygon math, no JavaScript data binding.
Token overrides — it's just CSS variables
All the colors, spacing, and radii are CSS custom properties. Override any of them locally — they cascade normally.
/* global theme tweak */
:root {
--st-accent: #00d4ff;
--st-bg: #0a0f1e;
}
/* local override — just for the dot */
.chart-dot {
--st-accent: var(--st-accent-2);
}
Multiple charts on the same page? Each container has its own --st-p1–--st-p8, so they're fully independent.
Category bars
The @st-cat-bar-fill mixin builds a gradient progress bar. You set the fill per element using a CSS variable — no extra params needed once the mixin is declared.
@st-cat-bar-fill(.bar-fill, 0)
/* per-bar widths */
.equities { --st-cat-bar-fill-range: 82%; }
.crypto { --st-cat-bar-fill-range: 61%; }
.forex { --st-cat-bar-fill-range: 45%; }
<div class="bar-track">
<div class="bar-fill equities"></div>
</div>
See it live
Live demo
GitHub — fscss-ttr/st-core.fscss (MIT)
FSCSS NPM (MIT)
The full demo includes stat cards, a chart with fill + line + dot + grid + axes, category bars, and a phone frame — all driven by @st-* mixins with no custom CSS beyond the mixin calls themselves.
Why FSCSS?
FSCSS is a lightweight modern CSS preprocessor.
If you're unfamiliar with FSCSS, the docs are a good starting point.
Drop a ⭐ on the repo if it's useful, and feel free to open issues or PRs — it's MIT, go wild.
Top comments (0)