I make dashboards. Sales, traffic, signups, the usual mess. I care about looks, but I also care about time. Can I ship fast? Will it run smooth on a phone? Will my boss say “wow” and not “ugh”?
So I tried a bunch of chart tools. I used them on real work. I broke some things. I fixed them. And yeah, I have feelings about it. (I documented the whole experiment in a no-fluff recap you can skim here.)
You know what? Pretty charts are nice. But clear charts feel even better. If you just want the easiest path to sane defaults, there's a quick checklist over here.
My quick wish list
- Clean by default
- Fast on mobile
- Dark mode that doesn’t look muddy
- Good tooltips (no tiny text)
- Exports that don’t blur when printed
- A path for big data, like 50k points
- Basic a11y (labels, focus, ARIA)
If you want a hosted, out-of-the-box option that already nails most of those bullets, give EJSchart a whirl. For a side-by-side look at seven popular libraries, check out this comparison.
That’s not a small ask. Still, a few tools got me close.
Chart.js — my easy go-to
I used Chart.js for a coffee shop dashboard. It showed daily revenue and average order size. I had two days to make it. Chart.js was like a buddy. It just worked.
What I like:
- Good defaults and quick wins
- Plugins for labels and notes
- The “tension” line looks smooth
- Built-in decimation helped with large sets
What bugged me:
- Big bundle if you add lots of plugins
- Past 50k points, it can drag
Here’s a small line chart I shipped. Pretty, soft, and readable.
<canvas id="revenue" height="160"></canvas>
<script>
const ctx = document.getElementById('revenue').getContext('2d');
const gradient = ctx.createLinearGradient(0, 0, 0, 200);
gradient.addColorStop(0, 'rgba(99,102,241,0.6)');
gradient.addColorStop(1, 'rgba(99,102,241,0.05)');
new Chart(ctx, {
type: 'line',
data: {
labels: ['Jan','Feb','Mar','Apr','May','Jun'],
datasets: [{
data: [12,19,9,17,23,28],
borderColor: '#6366f1',
backgroundColor: gradient,
fill: true,
tension: 0.35,
pointRadius: 2
}]
},
options: {
responsive: true,
plugins: {
legend: { display: false },
tooltip: { callbacks: { label: c => `$${c.parsed.y}k` } },
decimation: { enabled: true, algorithm: 'lttb' }
},
scales: {
y: { ticks: { callback: v => `$${v}k` } }
}
}
});
</script>
A tiny note: use system fonts and enough white space. It breathes better. Need more inspiration for gorgeous yet lightweight visuals? This walkthrough lays out the small tweaks that make charts pop.
ECharts — big, bold, and kind of fun
For a school site, I needed traffic charts with pan and zoom. Parents loved to pinch and zoom on phones. Apache ECharts felt flashy in a good way. The zoom tool and export button were a hit. For the scoop on how the biggest chart tool names stack up, see this field report.
Good stuff:
- Themes look rich
- Zoom and pan feel smooth
- Exports are crisp
- Huge data didn’t choke
Tough stuff:
- The API names are… a lot
- You’ll read the docs more than you want
Real code I used (trimmed):
<div id="traffic" style="height:280px;"></div>
<script>
var chart = echarts.init(document.getElementById('traffic'));
chart.setOption({
tooltip: { trigger: 'axis' },
toolbox: { feature: { saveAsImage: {} } },
dataZoom: [{ type: 'inside' }, { }],
xAxis: { type: 'category', boundaryGap: false, data: datesArray },
yAxis: { type: 'value' },
series: [{
name: 'Visits',
type: 'line',
smooth: true,
areaStyle: {},
emphasis: { focus: 'series' },
data: visitsArray
}]
});
</script>
I used the “dark” theme one night. It looked like a city at midnight. Kind of loved it.
D3 — total control, but bring snacks
I made a custom survey chart for a non-profit gala. They wanted a “lollipop” chart with cute dots. Off the shelf tools couldn’t do it. So, D3.
Why D3?
- You control every pixel
- Great scales and axes
- Can be small if you pick parts
But:
- You write more code
- Data joins take a minute to learn
My tiny lollipop sample:
<svg id="lolli" viewBox="0 0 420 200"></svg>
<script>
const data = [
{ label:'Food', value:82 },
{ label:'Music', value:67 },
{ label:'Decor', value:41 },
{ label:'Venue', value:74 }
];
const svg = d3.select('#lolli');
const x = d3.scaleLinear().domain([0,100]).range([100,380]);
const y = d3.scaleBand().domain(data.map(d=>d.label)).range([20,180]).padding(0.4);
svg.append('g').attr('transform','translate(0,0)')
.selectAll('line').data(data).join('line')
.attr('x1',100).attr('x2',d=>x(d.value))
.attr('y1',d=>y(d.label)+y.bandwidth()/2)
.attr('y2',d=>y(d.label)+y.bandwidth()/2)
.attr('stroke','#cbd5e1').attr('stroke-width',4);
svg.append('g').selectAll('circle').data(data).join('circle')
.attr('cx',d=>x(d.value))
.attr('cy',d=>y(d.label)+y.bandwidth()/2)
.attr('r',8).attr('fill','#10b981');
svg.append('g').attr('transform','translate(0,0)').call(d3.axisLeft(y));
svg.append('g').attr('transform','translate(0,180)').call(d3.axisBottom(x).ticks(5).tickFormat(d=>d+'%'));
</script>
It felt hand-made, which was the point. If you're hunting for open-source options beyond the usual suspects, this write-up might help: I tried a bunch of open-source JavaScript chart tools—here's what actually worked.
Recharts (React) — smooth in React land
My team ships React. Recharts fits that mood. It uses components, so state and props feel natural. Not the flashiest, but it’s calm and steady.
Pros:
- Great DX in React
- Composable parts
- Easy theming with CSS
Cons:
- Heavy sets can lag
- Less wild chart types
Tiny example:
<LineChart width={320} height={160} data={data}>
<XAxis dataKey="day" />
<YAxis />
<Tooltip />
<Legend />
<Line type="monotone" dataKey="orders" stroke="#f59e0b" dot={false} />
</LineChart>
I used this in a sales card list. It felt snappy.
Highcharts — polished, but watch the license
For a finance client, I used Highcharts Stock. The range selector and flags saved me hours. It looks fancy without much work. But heads up: you need a license for paid work.
What I saw:
- Great time series tools
- Crisp labels and exports
- A11y module is solid
Trade-off:
- Cost, of course
Want to stay in the free tier? There’s a rundown of no-cost libraries right here.
Plotly.js — science class energy
I used Plotly for
