About data-visualization
A skill for developers building data visualizations for dashboards and reports. It covers chart selection, responsive Recharts patterns, accessibility alternatives, and loading and empty states.
Key features
- 01Choose chart types for data patterns
- 02Reuse existing chart libraries and tokens
- 03Build responsive Recharts charts
- 04Provide screen-reader data alternatives
- 05Handle loading and empty states
Use cases
- 01Add trend charts to a dashboard
- 02Show compact sparklines beside statistics
- 03Make charts accessible without color-only cues
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ kensaurus/ skills --skill data-visualizationAfter installing, type/data-visualizationin Claude Code to confirm it loaded.
Bundled filesreferences/d3-and-accessibility.mdreferences/recharts.md
Details
From the project READMEData Visualization Skill
Degree of freedom: MIXED. Chart type and encoding [HIGH freedom];
existing-library/token probes and a11y fallback [LOW freedom — run exactly].
How to reason
- Observe — existing chart library, tokens, data shape
- Interpret — reuse a component vs new chart type
- Classify — line / bar / area / donut / sparkline / table-fallback
- Severity — inaccessible or empty-state-less chart outranks a missing gradient
Worked example
Observe:
package.jsonhas recharts; nosrc/components/charts; tokens define--primary. Interpret: reuse Recharts + tokens, not D3. Classify:ResponsiveContainerline chart + sr-only table; skeleton while loading. Verify: resizes; screen-reader table present; no second chart library.
Self-critique before reporting
- Existing lib — grepped
package.json; did not add a second chart library - Accessible — sr-only table or text alternative present
- States — loading + empty handled
- Right owner — event taxonomy →
audit-analytics; empty/loading frames →audit-ui-states
Create beautiful, accessible, and interactive data visualizations for dashboards and reports.
Product-event coverage ("are we tracking the right events?") is audit-analytics,
not this skill. Empty/loading chart frames are audit-ui-states.
Check existing first [LOW freedom — run exactly]
Before creating ANY visualization, verify:
- Check for existing chart libraries:
cat package.json | grep -i "recharts\|chart\|d3\|visx\|nivo\|tremor"
rg "LineChart|BarChart|PieChart" --type tsx -l | head -10
- Check for existing chart components:
ls -la src/components/charts/ src/components/dashboard/ 2>/dev/null
rg "ResponsiveContainer|Chart" --type tsx | head -10
- Check for design tokens:
cat tailwind.config.* | grep -A10 "chart\|colors"
Why: Use existing chart library and styling conventions.
Recharts (Recommended for React) [HIGH freedom]
- Wrap every chart in
ResponsiveContainer width="100%"; set a fixedheight. - Style through tokens:
hsl(var(--primary)),fill-muted-foreground,stroke-muted; no hard-coded hex. - Hide axis lines and tick lines (
tickLine={false} axisLine={false}); format Y ticks ($,%). - Custom
Tooltipcontent usesbg-background border rounded-lgso it matches the theme. - Chart types: line (trend over time), bar (
radius={[4,4,0,0]}, highlight the latestCell), area (gradient<defs>fill), donut (innerRadius/outerRadius+ centerLabelfor the total).
'use client'
import { LineChart, Line, XAxis, YAxis, Tooltip, ResponsiveContainer } from 'recharts'
export function RevenueChart({ data }: { data: { month: string; revenue: number }[] }) {
return (
<ResponsiveContainer width="100%" height={350}>
<LineChart data={data}>
<XAxis dataKey="month" tickLine={false} axisLine={false} className="text-xs fill-muted-foreground" />
<YAxis tickLine={false} axisLine={false} tickFormatter={(v) => `$${v}`} />
<Tooltip cursor={{ stroke: 'hsl(var(--muted))' }} />
<Line type="monotone" dataKey="revenue" stroke="hsl(var(--primary))" strokeWidth={2} activeDot={{ r: 6 }} />
</LineChart>
</ResponsiveContainer>
)
}
Full line chart with custom tooltip, bar, area-gradient and donut components: references/recharts.md §Line chart, §Bar chart, §Area chart, §Pie/Donut chart.
Sparklines (Mini Charts) [HIGH freedom]
- A
LineChartwith oneLine,dot={false},strokeWidth={1.5}, no axes, height ~40. - Map a
number[]to{ index, value }inside the component so callers pass plain arrays. - Place it in a
w-20slot beside the stat value, never as its own card.
Sparkline component and stats-card usage: references/recharts.md §Sparklines.
Stat Cards with Trends [HIGH freedom]
rounded-xl border bg-card p-6; title intext-muted-foreground, valuetext-3xl font-semibold.- Trend arrow +
Math.abs(change)%; green for up, red for down; pass the same color to the sparkline. sparklineDatais optional; render the sparkline only when present.
StatCard component: references/recharts.md §Stat cards with trends.
Real-time Data Updates [HIGH freedom]
- Append in
setData(prev => [...prev, point].slice(-N)); keep a bounded window (about 20 points). isAnimationActive={false}and a fixedYAxis domainso the chart does not jump per tick.- Clear the interval or socket subscription in the effect cleanup.
RealtimeChart component: references/recharts.md §Real-time data updates.
D3.js for Custom Visualizations [HIGH freedom]
- Reach for D3 only when Recharts cannot express the mark; never add it beside an existing chart library.
- Render into a
ref'd<svg>fromuseEffect;svg.selectAll('*').remove()before redrawing on data change. scaleBandfor categories,scaleLinear().nice()for values; size fromclientWidth/clientHeight, with margins.- Animate with
.transition().duration(750)from the baseline; color with the samehsl(var(--primary))tokens.
Full D3 bar chart component: references/d3-and-accessibility.md §D3.js custom bar chart.
Accessibility [LOW freedom — run exactly]
- Wrap the chart in
<div role="img" aria-label="...">that states what the chart shows and its range. - Mark the SVG chart
aria-hidden="true"; provide the data as ansr-only<table>with a<caption>. - Color is never the only encoding: pair it with labels, markers, or a legend.
<div role="img" aria-label="Revenue chart showing monthly data from January to December">
<ResponsiveContainer><LineChart data={data} aria-hidden="true">{/* ... */}</LineChart></ResponsiveContainer>
<table className="sr-only">
<caption>Monthly Revenue Data</caption>
<thead><tr><th>Month</th><th>Revenue</th></tr></thead>
<tbody>{data.map((d) => <tr key={d.month}><td>{d.month}</td><td>${d.revenue}</td></tr>)}</tbody>
</table>
</div>
Full accessibility block: references/d3-and-accessibility.md §Accessibility.
Validation [LOW freedom — do not skip]
After creating visualizations:
- Responsive → Charts resize properly on all screens
- Accessible → Screen reader alternatives provided
- Performance → Large datasets use virtualization/sampling
- Loading states → Skeleton shown while data loads
- Empty states → Meaningful message when no data
- Color contrast → Meets WCAG guidelines
- Tooltips → Provide detailed data on hover