From shipit-ui-design
Apply senior chart-design knowledge — pick-the-right-chart framework, color encoding, axis honesty, accessible alt-text, responsive sizing — when generating or refining charts in dashboards or files importing recharts, visx, tremor, echarts, chart.js.
How this skill is triggered — by the user, by Claude, or both
Slash command
/shipit-ui-design:data-visualizationThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Senior reference for charts in product UI. Assumes the reader can read a chart; the goal is to surface the encoding decisions, axis-honesty rules, and accessibility patterns that separate a credible chart from a pretty one.
Senior reference for charts in product UI. Assumes the reader can read a chart; the goal is to surface the encoding decisions, axis-honesty rules, and accessibility patterns that separate a credible chart from a pretty one.
- Max 300 lines per file. If a generated component would exceed, split before writing.
- No hardcoded design values. Colors, spacing, radii, shadows, durations, easings — all from tokens.
- Every interactive element has hover, active, focus-visible, and disabled states.
- All motion respects
prefers-reduced-motion.- Every image / illustration has alt text or
aria-hiddenif decorative.- Dark mode is never an afterthought — emitted alongside light from the start.
- Stack-respect: never introduce a new framework or styling system; adapt to what's there.
Charts answer questions. Pick the chart from the question, never from the data shape.
| Question | Default chart | Notes |
|---|---|---|
| How does X compare across categories? | Horizontal bar | Vertical only when categories ≤ 5 and labels are short |
| How does X change over time? | Line | Multi-series cap: 5 lines visible |
| How is X distributed? | Histogram or box plot | Bar chart over numeric bins ≠ histogram; spacing matters |
| What's the share of a whole? | Stacked bar (single bar) > pie | Pie only at ≤ 4 slices and parts that sum to 100% |
| How does X relate to Y? | Scatter | Add trendline only when correlation is genuine |
| Where are the hot spots? | Heatmap | Time × category matrix is its sweet spot |
| What's the flow between states? | Sankey | Reserve for genuine flows; not for everything-is-a-process |
| Hierarchical share? | Treemap | When tree depth ≤ 3 and area comparison matters |
| OHLC over time (finance)? | Candlestick | Reserved domain; do not adapt to non-finance |
When in doubt, a horizontal bar chart wins. It handles long labels, supports many categories, encodes a single number well, and is the most readable format. Full matrix in references/charts/chart-types.md.
Position is the strongest channel; length is next; angle/area are weak; color is the weakest. Encode the most important variable on the strongest channel available.
Never use color as the only channel for an encoding. Pair with shape, pattern, or label.
Three families, used for three jobs. Full token set in references/charts/color-encoding.md.
| Family | Use | Token shape |
|---|---|---|
| Categorical | Series in line/bar (≤ 8) | --chart-cat-1 … --chart-cat-8 (Okabe-Ito by default — colorblind-safe) |
| Sequential | Magnitude on heatmap, choropleth | --chart-seq-50 … --chart-seq-900 (single-hue ramp) |
| Diverging | Above/below baseline (gain/loss, sentiment) | --chart-div-low ↔ --chart-div-mid ↔ --chart-div-high |
Hard rules:
--color-success-600 / --color-danger-600 only when the symbol carries the meaning.Axis decisions are ethics decisions.
2.347 ….Numbers on a chart need context. Annotations carry that context.
--color-text-2, with a small label at the end.--color-surface-2 between bounds.Annotations belong to the chart, not the page. They go inside the SVG so they survive export.
Tooltips supplement; they never carry primary information.
A chart whose only legend is the tooltip is broken. Tooltips supplement an existing visible legend.
| Placement | Use |
|---|---|
| Above plot, left-aligned | Default — readable without eye travel |
| Right of plot | When categories > 4 and short |
| Below plot | Mobile, or when plot is wider than legend |
| Inline (label at end of line) | Line charts with ≤ 5 series — best legibility |
Inline labels at the end of each line beat any legend for line charts. Do this whenever space allows.
Interactive legends (click to toggle a series) are excellent — but the toggle state must persist for the session and be keyboard-reachable.
Every chart MUST have alt text. The pattern:
"[Chart type] showing [variable] over [domain]. [Headline insight]. [Range or notable point]."
Examples:
Beyond alt text, provide a "View as table" toggle on every chart. Screen-reader users, keyboard users, and analysts copying numbers all benefit.
<figure role="figure" aria-label="…">
<svg aria-hidden="true">…</svg>
<figcaption class="sr-only">[full description]</figcaption>
<button aria-controls="chart-table">View as table</button>
<table id="chart-table" hidden>…</table>
</figure>
Charts animate to communicate change, not to entertain.
prefers-reduced-motion.Tokens: --dur-150 / 300 / 600, --ease-out-quint, --ease-in-out-cubic — see references/charts/chart-motion.md.
A chart that only works at 1440 is a screenshot. Three sizes for one chart:
| Size | Width | Height | Decoration |
|---|---|---|---|
| Sparkline | 80–160 px | 24–40 px | No axes, no legend, no tooltip — context lives elsewhere |
| Card chart | 280–600 px | 160–240 px | Title outside, axes minimal, legend if needed |
| Full chart | ≥ 600 px | 280–360 px | Full title, axes, legend, annotations, tooltip |
Below 768 px:
Sparklines have no tooltip; their context lives in the surrounding KPI tile (label + value + delta). Don't rebuild a chart inside a sparkline.
Per spec section 11, do not lock a chart library in the design. Detect what the project already uses; if none, present 2–3 candidates and selection criteria, then ask.
| Library | Pick when |
|---|---|
| Recharts | React app, common chart shapes, declarative; team comfort matters more than custom needs |
| Visx | React app, custom or unusual encodings; team has bandwidth for low-level work |
| Tremor | React + Tailwind, dashboard-shaped primitives (KPI tile, area chart, donut), fast scaffolding |
| ECharts | Framework-agnostic, very large datasets, interactive features (zoom, brush, complex tooltips) |
| Chart.js | Framework-agnostic, simple charts, smallest bundle of the heavyweights |
Detection order: read package.json → if a chart lib is present, use it. If not, ask the user. Never silently install. Match the constitution's stack-respect rule (rule 7).
monotone/spline) on time series — invents data points between actual values.npx claudepluginhub shipiit/shipit-ui-design --plugin shipit-ui-designSearches MemPalace before answering questions about past work, people, projects, or prior decisions. Returns verbatim stored content instead of guessing from model memory.
Guides Payload CMS config (payload.config.ts), collections, fields, hooks, access control, APIs. Debugs validation errors, security, relationships, queries, transactions, hook behavior.
Implements vector databases with Pinecone, Weaviate, Qdrant, Milvus, pgvector for semantic search, RAG, recommendations, and similarity systems. Optimizes embeddings, indexing, and hybrid search.