skills/charts/SKILL.md
Data visualization and charting best practices. Use when: choosing a chart type for data, configuring axes, adding tooltips, implementing chart theming for dark mode, connecting chart colors to application design tokens, formatting axis tick values, making charts accessible, auditing existing charts for readability and accessibility, or improving chart consistency across an application.
npx skillsauth add michaelsvanbeek/personal-agent-skills chartsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use Recharts for React applications. It is composable, SSR-compatible, and exposes styling through React props and CSS variables, making theme integration straightforward.
npm install recharts
Choose the chart type that matches the structure and purpose of the data:
| Chart Type | Use When | |------------|----------| | Line | Continuous data over time; trends, progressions | | Area | Like line, but emphasize magnitude or cumulative volume | | Bar (vertical) | Comparing discrete categories; ranking | | Bar (horizontal) | Comparing long category names; rankings where label length matters | | Stacked bar | Part-to-whole comparison across multiple series | | Scatter | Correlation between two continuous variables | | Bubble | Correlation with a third magnitude dimension | | Pie / Donut | Part-to-whole for a small number of categories (≤5); avoid for comparisons | | Heatmap | Two-dimensional distribution, intensity, frequency matrix | | Histogram | Distribution of a single continuous variable | | Gauge | Single metric against a target or range; dashboards |
"Disk Usage (GB)", "Response Time (ms)", "Requests / sec""Value", "Y", or no label at alltickCount and domain={['auto', 'auto']} or domain={[0, 'auto']}. For explicit control:<YAxis
tickCount={5}
domain={[0, 'auto']}
tickFormatter={(value) => formatMetric(value)}
label={{ value: 'Disk Usage (GB)', angle: -90, position: 'insideLeft' }}
/>
tickCount or rotate as a last resort.Every chart must include a tooltip that appears on hover/focus.
Intl.NumberFormat (locale-aware, not hardcoded separators).Intl.DateTimeFormat matching the granularity of the x-axis.const formatNumber = (value: number, unit?: string) =>
new Intl.NumberFormat(undefined, { maximumFractionDigits: 2 }).format(value) +
(unit ? ` ${unit}` : '');
const formatBytes = (bytes: number) => {
if (bytes >= 1e9) return `${formatNumber(bytes / 1e9)} GB`;
if (bytes >= 1e6) return `${formatNumber(bytes / 1e6)} MB`;
return `${formatNumber(bytes / 1e3)} KB`;
};
const formatDate = (ts: number) =>
new Intl.DateTimeFormat(undefined, { dateStyle: 'medium', timeStyle: 'short' }).format(ts);
const ChartTooltip = ({ active, payload, label }: TooltipProps<number, string>) => {
if (!active || !payload?.length) return null;
return (
<div className="chart-tooltip">
<p className="chart-tooltip__label">{formatDate(label)}</p>
{payload.map((entry) => (
<p key={entry.name} style={{ color: entry.color }}>
{entry.name}: {formatBytes(entry.value ?? 0)}
</p>
))}
</div>
);
};
<Tooltip content={<ChartTooltip />} />
Charts must read from the application's design token system — never use hardcoded colors.
Define chart-specific tokens alongside your global theme tokens:
:root {
--chart-axis-color: #6b7280;
--chart-grid-color: #e5e7eb;
--chart-tooltip-bg: #ffffff;
--chart-tooltip-border: #e5e7eb;
--chart-tooltip-text: #111827;
/* Series palette — ordered by typical usage priority */
--chart-color-1: #3b82f6;
--chart-color-2: #10b981;
--chart-color-3: #f59e0b;
--chart-color-4: #ef4444;
--chart-color-5: #8b5cf6;
--chart-color-6: #06b6d4;
}
@media (prefers-color-scheme: dark) {
:root {
--chart-axis-color: #9ca3af;
--chart-grid-color: #374151;
--chart-tooltip-bg: #1f2937;
--chart-tooltip-border: #374151;
--chart-tooltip-text: #f9fafb;
--chart-color-1: #60a5fa;
--chart-color-2: #34d399;
--chart-color-3: #fbbf24;
--chart-color-4: #f87171;
--chart-color-5: #a78bfa;
--chart-color-6: #22d3ee;
}
}
Read CSS variable values at render time to pass as props:
const useCSSVar = (name: string) =>
getComputedStyle(document.documentElement).getPropertyValue(name).trim();
function ThemedChart() {
const axisColor = useCSSVar('--chart-axis-color');
const gridColor = useCSSVar('--chart-grid-color');
const color1 = useCSSVar('--chart-color-1');
return (
<LineChart data={data}>
<CartesianGrid stroke={gridColor} strokeDasharray="3 3" />
<XAxis tick={{ fill: axisColor }} axisLine={{ stroke: axisColor }} />
<YAxis tick={{ fill: axisColor }} axisLine={{ stroke: axisColor }} />
<Line type="monotone" dataKey="value" stroke={color1} />
</LineChart>
);
}
Style the tooltip container via CSS classes that reference design tokens:
.chart-tooltip {
background: var(--chart-tooltip-bg);
border: 1px solid var(--chart-tooltip-border);
color: var(--chart-tooltip-text);
border-radius: 6px;
padding: 8px 12px;
font-size: 13px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
--color-danger).<figure> element with a <figcaption> describing what the chart shows.role="img" and aria-label to the chart's root SVG element with a summary of the data.<figure>
<ResponsiveContainer width="100%" height={300}>
<LineChart data={data} role="img" aria-label="Disk usage over the past 30 days, peaking at 87 GB on March 15.">
{/* ... */}
</LineChart>
</ResponsiveContainer>
<figcaption className="sr-only">
Line chart showing disk usage from March 1 to March 30. Values range from 42 GB to 87 GB.
</figcaption>
</figure>
<ResponsiveContainer width="100%" height={height}> — never hardcode pixel widths.height based on the chart type:
tickCount, hide secondary gridlines, or abbreviate labels.isAnimationActive={false} for charts that update frequently (dashboards, live data) to avoid re-animation on every data refresh.useMemo to avoid unnecessary recalculations on unrelated re-renders.development
TypeScript coding standards and type safety conventions. Use when: creating TypeScript files, defining interfaces and types, writing type-safe code, reviewing TypeScript for type correctness, auditing a codebase for type safety gaps, eliminating any or ts-ignore usage, or improving strict-mode compliance. Covers strict typing, avoiding any and ts-ignore, discriminated unions, Zod runtime validation, immutability patterns, and proper type definitions.
testing
Writing clear, actionable tickets in any issue tracker (Jira, Linear, GitHub Issues, ServiceNow, etc.). Use when: creating epics, stories, tasks, bugs, or spikes; writing acceptance criteria; decomposing work for a sprint; linking dependencies between tickets; auditing backlog items for clarity; or coaching a team on ticket quality. Covers title conventions, description templates, acceptance criteria, decomposition rules, dependency linking, and org-specific pluggable configuration.
development
Testing strategy, patterns, and evaluation for software and LLM/AI systems. Use when: writing tests, choosing test boundaries, designing test data, structuring test suites, evaluating LLM outputs, building evaluation pipelines, setting coverage thresholds, auditing test coverage gaps in existing projects, or improving test quality and structure.
development
Writing effective status updates for different audiences and cadences. Use when: writing a weekly status update, preparing a monthly summary, drafting a quarterly review, sending updates to leadership, sharing progress with stakeholders, or improving the clarity and impact of team communications. Covers weekly, monthly, and quarterly formats tailored for upward, lateral, and downward communication.