# @elabs-ai/components-charts > MetricCard, MetricGrid, ChartCard, ChartFrame (expand/flip/download). Import from `@elabs-ai/components-charts`. Part of brand-ui — see the root `llms.txt` for routing. ## Components - ANALYTIC_DASH - ANALYTIC_INK - ANALYTIC_MUTED_INK - AnalyticSeriesLayer - ANNOTATION_ANCHORS - AnnotationKey - Area - AREA_GESTURES - AreaBand - AreaChart — Cumulative or part-of-whole trend over time — a filled line. - avoid: Stacking areas that are not parts of one whole — a stack asserts summation; use lines. - avoid: Overlapping opaque areas — either stack them or switch to a LineChart. - avoid: Leaving status="loading" unhandled — AreaChartLoading is the shipped skeleton. - AreaChartLoading - AutoChart — Spec-driven chart — hand it a serializable ChartSpec and it picks and renders the right chart. - avoid: Hand-picking a chart type when the spec already encodes the intent — AutoChart is the agent-facing entry point. - avoid: Putting raw colors in a spec's series — the chart-1…chart-5 tokens are the palette in every theme. - avoid: Passing an empty dataset with no not-ready signal — render the loading state instead of an empty frame. - Bar - BarChart — Categorical comparison — composed from Bar + BarXAxis/BarYAxis inside its provider. - avoid: Truncating the value axis so small differences look large — a bar axis starts at zero. - avoid: Hardcoding series colors — use the chart-1…chart-5 tokens so every theme works. - avoid: Rendering an empty frame before data arrives — use the shipped chart skeleton utilities. - BarValueAxis - BarXAxis - BarYAxis - BulletChart - BumpChart — Rank over discrete time — who is #1 changes over time. variant="lines" plots the trajectory (rank as an inverted y-axis); variant="strip" is the G21 filmstrip (fixed rows, shade + a printed number carry the per-period rank). - avoid: Passing neither valueKey nor rankKey — there is no honest rank to derive, and every row is silently dropped rather than plotting a guessed order. - avoid: Mixing rankKey and valueKey inconsistently across periods — rankKey, when present, wins outright per row; a dataset that supplies rank for some periods and expects value-derived rank to fill the rest will jump between two different orderings. - avoid: Choosing variant="lines" for more than ~10-12 entities — crossing lines stop being followable well before maxEntities' default cap of 10 kicks in; variant="strip" reads a crowded field better because rows never move. - avoid: Reading the strip's row POSITION as the current rank — rows are fixed at each entity's FINAL rank; only the cell shade and its printed number carry the rank at any other period. - CALENDAR_MIN_ROWS - CALENDAR_ROWS - Candlestick - CandlestickChart — Open–high–low–close price bars over time, one candle per period, with volume and moving averages as optional overlays. - CANVAS_LAYER_DEFAULT_MARGIN - CANVAS_LAYER_ENTER_MS - CANVAS_LAYER_HIT_RADIUS - CanvasLayer — The canvas mark path for ChartFrame — a drop-in sibling of the SVG marks for views past what the DOM can carry (~20k marks up), with a spatial-grid hit test and a one-tab-stop virtual cursor. - avoid: Reaching for it below ~20k marks — the SVG path is inspectable, stylable and testable, and ChartDatapointLayer already gives every point a real keyboard target. A canvas is what you accept when the DOM has run out, not an upgrade. - avoid: Backing hitTest with a linear scan over the points — it runs on every pointermove, so at 50k points the hover path, not the draw, is what makes the canvas view feel worse than the SVG one it replaced. Use createSpatialGrid. - avoid: Shipping it without accessibleDescription — canvas pixels are invisible to assistive technology, so with no parallel summary the marks simply cease to exist for a screen-reader user. That is the one failure this component cannot recover from on the reader's behalf. - avoid: Hardcoding a colour in draw (a hex, an rgb()) instead of canvasTokenColor — the layer redraws on a theme flip, which repaints exactly the same wrong colours. - avoid: Registering one ChartDatapointLayer target per point to 'get keyboard for free' — that is the DOM cost the canvas exists to avoid; the virtual cursor is the contract here. - CATEGORICAL_SOFT_CAP - CHART_BREAKPOINT_THRESHOLDS - CHART_BREAKPOINTS - CHART_CLIP_PASSTHROUGH - CHART_DENSITY_SM_MAX_TICKS - CHART_HAIRLINE_WIDTH - CHART_SPEC_PALETTES - CHART_STAGGER_BAR_MS - CHART_STAGGER_DOT_MS - CHART_TYPES - ChartAnnotations - ChartBrush — A drag-to-select range control under a chart that zooms the plot above to the brushed window. - ChartBrushLayout - ChartBrushSelectionOverlay - ChartBrushTrackOverlay - ChartCard — Titled card surface around a chart — header, description, and the chart body. - avoid: Nesting a ChartCard inside a Card — it already IS the surface. - avoid: Hand-building expand / flip-to-table / download controls on the card — wrap it with ChartFrame instead. - avoid: Leaving the body blank when data is absent — render the loading/empty state; a blank card reads as broken. - ChartConfigProvider - ChartDatapointLayer — The keyboard/AT half of the chart interaction contract — real buttons in a sibling layer over the aria-hidden chart SVG (#349). - avoid: Putting tabIndex on an SVG shape instead — every chart body is aria-hidden, so a focusable child inside it is the axe aria-hidden-focus violation, and axe is blocking here. - avoid: Letting the layer take pointer events — it is pointer-events:none so the SVG underneath keeps mousemove; swallowing them silently kills hover tooltips on line/area charts. - avoid: Giving every datapoint its own tab stop — the layer is a roving tabindex (one target at 0, the rest -1, arrows to move); a 500-point series must not add 500 tab stops. - avoid: Measuring target geometry with getBBox/getBoundingClientRect — targets carry the geometry the shapes already computed from the scales; a layout read in render is the banned path. - ChartDatapointProvider — Opt-in wrapper that makes a chart's datapoints activatable — mounted only when the consumer passes onDatapointClick or copyValueOnActivate. - avoid: Mounting it around every chart by default — a chart with no drill-down handler adds no context, no layer and no DOM, and that opt-out path is the point. - avoid: Rendering more than ~500 targets — the provider warns in dev because a keyboard target per datapoint stops being navigable long before it stops rendering. - avoid: Reading the click handler out of a state variable that changes every render — the provider keeps the context value stable via refs so an inline arrow function does not churn every shape. - ChartFallback - ChartFrame — Opt-in chart wrapper adding expand / flip-to-table / download-CSV to any chart child. - avoid: Expecting ChartFrame to read the chart's context — it is the PARENT of the chart's provider; pass the same data to both via props. - avoid: Importing @elabs-ai/components-data into a chart — charts → ui only; flip-to-table uses the @elabs-ai/components-ui Table. - avoid: Expecting the table/download controls with no `data` — they hide by design when data is absent or empty; pass the same rows you gave the chart. - ChartLegend — Series key with label, value and an optional progress bar; pattern-aware under decoration. - avoid: Dropping the legend on a multi-series chart — colour without a key is not a legend. - avoid: Ordering legend items differently from the series — the eye maps them positionally. - avoid: Passing a raw hex as the item colour — resolve the chart token so high decoration gets its pattern swatch. - ChartLegendHoverProvider - ChartLoadingLabel - ChartMarkers - ChartMarkGeometryProvider - ChartMultiples - ChartNavigator - ChartProvider - ChartRevealClip - CHARTS_A2UI_BINDINGS - CHARTS_A2UI_CATALOG_SCHEMA - ChartSelectionGestureHitArea - ChartSelectionGestureHost - ChartSelectionGestureLayer - ChartSelectionGesturePlotLayer - ChartSelectionGestureScope - ChartSelectionToolbar - ChartStatFlow - ChartTooltip — Hover readout for the point/series under the pointer. - avoid: Putting information ONLY in the tooltip — hover content is unreachable by keyboard and on touch. - avoid: Showing every series in a shared tooltip on a dense chart — filter to the hovered series. - avoid: Formatting numbers by hand — use Intl so locale and units stay consistent with the axis. - ChartTooltipBox - ChartTooltipContent - ChartTooltipDot - ChartTooltipIndicator - ChartTooltipInline - ChartTooltipTable - ChoroplethChart — Region-shaded map for a measure that is defined per geographic area. - avoid: Shading raw counts instead of a rate — area size becomes the story and the map lies. - avoid: A rainbow ramp for a sequential measure — use one ordered ramp so darker always means more. - avoid: Shipping it without a legend — a shaded region carries no value without the scale. - ChoroplethFeatureComponent - ChoroplethGraticule - ChoroplethProvider - ChoroplethTooltip - CLICK_HIT_RADIUS - CLICK_SENSITIVITY - ComposedChart — One cartesian frame that layers several series types (bars + lines + areas) together. - avoid: Stacking series on two silently-different y-scales — label the second axis or the comparison lies. - avoid: Layering more than ~3 series types in one frame — split it into small multiples instead. - avoid: Colouring series by hand — resolve --chart-1..5 so the dark theme stays legible. - CONTINUOUS_MIN_OPACITY - CustomShapes - DateTicker - DEFAULT_CHART_CONFIG - DEFAULT_CHART_INTERACTIONS - DEFAULT_CHART_LIFECYCLE - DEFAULT_CHART_PLOT_HEIGHT - DEFAULT_CHART_STATUS - DEFAULT_CHOROPLETH_LEGEND_POSITION - DEFAULT_CHOROPLETH_ZOOM_LABELS - DEFAULT_CIRCULAR_CURVENESS - DEFAULT_DESCRIBE_SERIES_PHRASES - DEFAULT_FORCE_SEED - DEFAULT_HEATMAP_STEPS - DEFAULT_HOVER_OFFSET - DEFAULT_INDEX_MIN_SPAN - DEFAULT_MAX_INTERACTIVE_DATAPOINTS - DEFAULT_PIE_LABEL_MIN_ANGLE - DEFAULT_SCATTER_SIZE_RANGE - DEFAULT_SYMBOL_MAX_SIZE - DEFAULT_WHISKER_MULTIPLIER - DEFAULT_Y_AXIS_ID - DEFAULT_Y_DOMAIN_TWEEN_MS - DENSITY_OUTSIDE_ID - DENSITY_ROWS_WARN_AT - DENSITY_SHAPE_CYCLE - DENSITY_SHAPES - DensityScatterChart — A point plot for 10⁵–10⁶ rows: every point drawn, its colour the density around it, zones on the axes classifying it, and an intersection selection (x range × y range × lasso × zone). WebGL dots, screen-space bins, Canvas-2D fallback. - avoid: Under ~20k points — ScatterChart has labels, shapes, trends and per-point marks this canvas path cannot. - avoid: Handing 10⁵ rows as objects — pass columnar data ({ x, y, values }) or pay for the per-row objects before the first pixel. - avoid: A second hue for density — density is lightness on the class hue; a rainbow ramp misreads as categories. - avoid: Averaging once a size limit is hit — the chart's point is that it never does; bin size stays in screen pixels, not data units. - DensityShapeGlyph - DistributionChart — One numeric variable, optionally by group, read four ways on one shared scale — histogram, box, violin or strip. - avoid: kind="violin" on a handful of records — a density estimate from ~12 points draws the bandwidth, not the data; below roughly 50 per group use kind="strip", where every record is its own mark. - avoid: Leaving the Silverman default bandwidth on visibly bimodal data — the rule of thumb over-smooths two modes into one bulge and loses ~2% of the mass off the grid. Pass `bandwidth` when the shape is the point. - avoid: kind="box" where the reader needs the individual records — the five-number summary hides bimodality completely. Under ~150 per group, kind="strip" shows the same numbers without discarding them. - avoid: Comparing a violin's axis against another kind's as if it were the same scale — violin is the one kind that widens the domain (by 1.6 bandwidths, so the silhouette is not clipped into a bar); histogram, box and strip share the data's own extent. - avoid: Passing `bins` as an edge list that does not cover the data — an explicit array is the FULL edge list, and a value outside it is DROPPED (with a dev warning), never absorbed into an end bucket. Pass a bin COUNT unless the edges carry business meaning. - DrawPath — A path that draws itself in through pathLength 1 — no measurement step, and a real reduced-motion branch rather than a shorter duration. - avoid: Filling it — a dash offset acts on the stroke, so a filled path appears in a single frame and the draw-in does nothing at all. - avoid: Measuring the geometry with getTotalLength to drive the animation — pathLength 1 exists to avoid it. That measurement is a layout read in render, and it returns 0 under jsdom, so every mocked test would draw nothing. - avoid: Shortening the duration instead of branching for reduced motion — a motion path at duration 0 still leaves the dash attributes in the DOM, and a stroke carrying a dash array is one rounding error away from a visible seam. The reduced-motion state has to be the ordinary, undecorated path. - avoid: Letting meaning depend on the animation having run — a reader who arrives after it finished, or who never sees it, must lose nothing. - DumbbellChart — Before/after (or this-year/last-year) per category — a track with two markers and the delta between them, so the CHANGE is the mark, not a second bar. variant="slope" swaps the per-category track for two shared value columns. - avoid: Using variant="slope" past the 8-row soft cap — the crossing lines stop being decodable at that density (it dev-warns once); switch to the default variant="dumbbell" (rows) instead of reading the warning as noise. - avoid: Picking a beads.unit so small that round(delta / unit) draws dozens of dots — past a few tens of units a UnitStack reads as a texture smear, not a count; choose a coarser unit and say so in the caption. - avoid: Passing more than 2-3 extraKeys — every extra competitor dot draws on the SAME track as the primary pair, and past a couple they overlap the very marker they were meant to contextualize. - avoid: Turning on showDelta with many closely-spaced rows — the delta label sits fixed beside the end marker with no collision avoidance of its own (unlike the slope columns' spaceSlopeLabels pass), so a small aspectRatio with many rows will overlap labels. - END_LABEL_MIN_GAP - ErrorBars - FACET_BASELINE_KEY - FACET_DEFAULT_COLUMNS - FACET_DEFAULT_PANEL_HEIGHT - FORCE_ALPHA_MIN - FORCE_GRAVITY - FORCE_TICK_BUDGET - FunnelChart — Stage-by-stage drop-off through an ordered pipeline. - avoid: Using it for unordered categories — a funnel asserts a sequence; unordered data belongs in a bar chart. - avoid: Encoding stage identity by colour alone — label each stage; colour is not a legend. - avoid: Hiding the absolute counts behind percentages only — a funnel without its base number cannot be judged. - Gantt (density=comfortable*|compact) — Schedule grid — tasks as bars over time, with a task table beside them. - avoid: Mutating task dates inside the component on drag — Gantt is emit-only; the app owns the model (D5). - avoid: Bar labels that rely on the bar fill for contrast — check the label against the bar color in every theme. - avoid: Rendering the grid without status="loading" while rows are still fetching — skeleton rows must hold the layout. - GANTT_NOMINAL_VIEWPORT_PX - GANTT_UNIT_MS - Gauge — Single-value dial against a known range — a KPI with an explicit ceiling. - avoid: A gauge for a value with no meaningful maximum — that is a MetricCard, not a dial. - avoid: A gauge per KPI in a grid — a row of dials reads worse than a MetricGrid; use one for the headline only. - avoid: Encoding the threshold by colour alone — pair the band with a label or a tick. - GESTURE_FILL_OPACITY - GESTURE_HALO_WIDTH - GESTURE_OUTLINE_WIDTH - GestureOverlay - GOLDEN_ANGLE_RAD - GradientDarkgreenGreen - GradientLightgreenGreen - GradientOrangeRed - GradientPinkBlue - GradientPinkRed - GradientPurpleOrange - GradientPurpleTeal - GradientSteelPurple - GradientTealBlue - Grid - HAIRLINE_HATCH_OUTLINE_WIDTH - HairlineFloor — One tick per calendar period along the foot of a plot, every n-th drawn longer — the passage of time in 0.55px of ink, with nothing to read. - avoid: Decimating the ticks to make them fit — one tick per period, always. An irregular floor reads as missing data, and dropping ticks silently costs the reader the duration the mark exists to show. Too many periods to draw means the chart is too small for this mark. - avoid: Using it where the reader needs to know WHICH date — a floor answers how long, an axis answers when. If labels are wanted the answer is XAxis, not a longer floor. - avoid: Choosing every for looks — the long tick is the only navigational cue on the mark, so it has to land on a boundary the reader already holds: 12 for months, 7 for days, 4 for quarters. - avoid: Painting it at series weight — at var(--chart-foreground) the floor stops being a rule and becomes a second data row along the bottom. - HaloText — SVG text that punches a plot-ground halo out from behind itself, so a label stays readable directly ON a mark instead of beside it. - avoid: Hard-coding a paper colour for the halo — the halo IS the plot ground, so a literal white one becomes a white smear the moment the theme goes dark. It defaults to var(--chart-background) for that reason; an override names another token, never a colour. - avoid: Reaching for it to rescue low-contrast text — the halo separates a label from BUSYNESS, not from its ground. The ink still has to clear 4.5:1 against the card; a halo over a 3:1 label is still a 1.4.3 failure. - avoid: Widening the halo until labels stop colliding — the visible outline is half the width, so a wide one starts eating glyph counters and neighbouring letters. Move the label or drop one; 3px is the calibrated value. - avoid: Letting it carry the only copy of a number — the chart body is aria-hidden, so a halo label reaches no screen reader. Repeat the figure in the caption, the summary or the flip-to-table view. - HeatmapChart — Two discrete dimensions × one value — weekday × hour, product × region, or a year of days. - avoid: steps: 0 (the continuous ramp) when the reader must compare exact values — opacity is not countable; keep the stepped ramp or turn labels on. - avoid: emptyValue="blank" on data that contains real zeroes — a measured zero then looks identical to a missing row, which is the one thing the pinprick exists to prevent. - avoid: Forcing the calendar variant into a narrow box (overflow-hidden, a tall aspectRatio) — it enforces a minimum width and scrolls on purpose; squeezed day cells fall below the 24px target size. - avoid: Leaning on the darkest ramp step to say "this is the peak" — colour alone; highlight draws the ring, and a diverging palette needs labels or its negative hatch for sign. - InlineChip - KDE_GRID_POINTS - KDE_TAPER - KEYBOARD_RECT_IDLE - LASSO_SIMPLIFY_EPSILON - LASSO_SNAP_DISTANCE - Leader — The dashed hairline that ties an annotation to the mark it describes — an elbow or a curve, in one of two dash rhythms. - avoid: Thickening it so the connection is easier to follow — at series weight a leader stops being furniture and starts being read as data. If it is hard to follow, the label is too far away. - avoid: Inventing a third dash rhythm — the union is 1 3 (quiet) and 2 3 (emphatic) on purpose. Sixty-three templates each picking their own dash array is the drift this layer exists to prevent. - avoid: Copying the path but not the unset fill — an elbow is an OPEN path, and an open path that is filled paints a solid triangle between its two ends. The component sets it; hand-rolled copies routinely do not. - avoid: Routing it across the series it points at — at this weight a leader that overlaps the data is indistinguishable from a gridline. Bend the elbow around instead. - Legend - LegendItemComponent - LegendLabel - LegendMarker - LegendProgress - LegendValue - Line - LinearGradient - LineChart — Trend over a continuous (usually time) axis. - avoid: A LineChart over unordered categories — a line asserts continuity; use a BarChart. - avoid: More than ~5 series in one plot — past the chart-1…chart-5 palette the series stop being distinguishable; facet instead. - avoid: Distinguishing series by color alone — add markers or direct labels for non-color users. - LineChartLoading - LineLoadingPulseStroke - LiveLine - LiveLineChart — A line chart that appends points as they arrive and keeps a sliding time window, for streaming metrics. - LiveXAxis - LiveYAxis - LONG_PRESS_MS - Marginalia — An italic note in the margin, tied to its mark by a Leader — the analyst's own remark on a printed chart. - avoid: Reaching for foreignObject to get HTML wrapping — it does not survive the download-as-image path, renders inconsistently across engines, and smuggles AT-visible, focusable HTML into the aria-hidden chart body, which is the axe aria-hidden-focus violation this package treats as a red build. Pass tspans for a second line. - avoid: Using it for a value — a value belongs ON its mark as HaloText. Marginalia carries a JUDGMENT the data cannot state by itself, which is the whole reason it is set in the analyst's voice. - avoid: More than one or two per chart — a margin note is why a reader trusts the chart; a margin full of them is an essay with a plot in it. - avoid: Leaving a caveat here and nowhere else — the chart body is aria-hidden, so the note reaches nobody using a screen reader. - MarkerGroup - MarkerTooltipContent - MAX_PLACE_LABELS - MetricCard — Single KPI tile — label, value, delta/trend. - avoid: Numbers without tabular-nums — figures jitter across a row; use tabular-nums for any number column. - avoid: Encoding up/down by color alone — pair with an arrow/sign. - avoid: Re-declaring a KPI tile in another package — MetricCard is owned by @elabs-ai/components-ui; charts and editor re-export it (ADR 0012). - MetricGrid — Responsive grid of KPI tiles — the summary row at the top of a dashboard. - avoid: More than ~5 tiles in one row — KPIs answer 'how are we doing', not 'everything we measure'. - avoid: Numbers without tabular-nums — figures jitter across the row. - avoid: Re-declaring a KPI tile locally — MetricCard is owned by @elabs-ai/components-ui and re-exported here (ADR 0012). - MIN_DATAPOINT_TARGET_SIZE - NAVIGATOR_BAR_HEIGHT - NAVIGATOR_BUCKET_PX - NAVIGATOR_HANDLE_TARGET - NAVIGATOR_HEIGHT - NAVIGATOR_HEIGHT_NARROW - NETWORK_DEFAULT_MAX_NODES - NETWORK_DEFAULT_NODE_RADIUS - NETWORK_LABEL_GAP - NETWORK_MAX_LABEL_GUTTER_FRACTION - NETWORK_MAX_NODE_RADIUS - NETWORK_MIN_NODE_RADIUS - NETWORK_PADDING - NetworkChart — A node-link graph in three layouts — a settled force cloud, a ring of chords, or a bipartite colonnade — with hover/focus adjacency emphasis. - avoid: Reading a force layout's POSITIONS as data — only adjacency is encoded; distance, direction and the picture's orientation are artefacts of the solver's seed. Use layout="circular" or "arc" whenever position must mean something. - avoid: Labelling every node past roughly 15 — set `labelThreshold` so only the nodes worth naming carry text; the datapoint targets already announce every node to a screen reader. - avoid: Reaching for layout="arc" on a graph that is not bipartite — the two columns are DERIVED (exactly two groups, else the nodes that are only ever a link source go left), so a general graph draws a colonnade that asserts a split the data does not have. - avoid: Turning `draggable` on and expecting the dragged position to persist — a node springs back on release because the settled layout is the answer; a pinned position would be a claim about the data that the layout never made. - avoid: Passing thousands of nodes because `maxNodes` is only a warning — the force solve is synchronous, so past a few hundred nodes it blocks the frame that renders it. Aggregate into hubs before the chart, not inside it. - NO_MODIFIERS - PARALLEL_COORDINATES_MAX_DIMENSIONS - PARALLEL_COORDINATES_MIN_DIMENSIONS - ParallelCoordinatesChart — Same entities across 3-6 mixed-unit dimensions: one hairline per entity threaded through per-axis-normalized vertical scales, so shape and crossing pattern reveal correlation across axes that share no common unit. - avoid: Fewer than 3 or more than 6 dimensions — below 3 a DumbbellChart (2) or MetricCard (1) reads better; above 6 the axes crowd and `resolveParallelDimensions` clamps to the first 6 with a console warning, silently dropping the rest. - avoid: Dimensions on wildly different natural scales with no explicit `domain` — each axis normalizes independently, so an unset domain just uses that dimension's own min/max, which is usually right; only override when you need a domain that isn't in the data (e.g. a known 0-100 ceiling). - avoid: Using `highlightKey` to try to promote MULTIPLE entities to hero status — only the first row a predicate matches (or the one literal id) is promoted; for comparing several entities at once, dim the rest via a different technique or fall back to small multiples. - avoid: Reaching for this when the entities do NOT share the same dimensions, or when there is only one entity — a single-entity profile across many metrics is a RadarChart (shared 0-100 radial scale) or a MetricGrid, not a parallel-coordinates plot. - PatternArea - PatternCircles - PatternHexagons - PatternLines - PatternWaves - PeakRing — A dashed outline around the one mark that matters — the peak, the outlier, the cell the caption is about. - avoid: Swapping the dash for a highlight hue — the ring exists because emphasis by SHAPE survives greyscale and a colour-blind reader (WCAG 1.4.1). Recolouring it throws away the only reason to reach for it. - avoid: Ringing three marks — the ring points at whatever the caption is about. A second ring halves the emphasis and a third deletes it. - avoid: Treating the ring as the statement — it is aria-hidden furniture that points; it says nothing. A peak worth ringing is worth writing in the caption or the summary. - avoid: Dashing a plotted mark elsewhere in the same chart — nothing that carries data is dashed here, and that is precisely what stops the ring being read as a series. - PieCenter - PieCenterShell - PieChart — Part-of-whole split across a handful of categories. - avoid: More than ~5 slices — a bar chart compares better; a pie is not a ranking. - avoid: A pie for values that don't sum to a meaningful whole. - avoid: Identifying slices by color alone — put the label and value on or beside the slice. - PieLabels - PieProvider - PieSlice - POOLED_KEY - PROFIT_LOSS_LEGEND_ITEMS - PROFIT_LOSS_NEGATIVE_COLOR - PROFIT_LOSS_POSITIVE_COLOR - PROFIT_LOSS_TOOLTIP_LABEL_FALLBACK - ProfitLossLegend - ProfitLossLegendHoverProvider - ProfitLossLine - QUIET_DOT_SIZE - QuietDot — The 0.9px pinprick that renders a measured null or zero, so an empty cell in a matrix is never a hole. - avoid: Scattering it as decoration — it has ONE job, and it is the null/zero render. A pinprick that is not standing for an absent value teaches the reader that absence is noise. - avoid: Leaving a zero cell blank instead — blank reads identically to no data collected, to the grid ends here, and to a rendering bug. The dot says the cell was visited and the answer was nothing. - avoid: Assuming it distinguishes 0 from null — it says MEASURED, not which. Where the difference is load-bearing keep the dot for the zero, give the missing cell a hatch or an explicit gap, and say so in the legend. - avoid: Enlarging it so it is easier to see — an absence rendered at the weight of a value becomes a value. - RadarArea - RadarAxis - RadarChart — Multi-metric profile comparison on a shared radial axis. - avoid: Plotting metrics with different units on one radar — normalize first or the shape is meaningless. - avoid: Overlaying more than ~3 profiles — the filled areas occlude each other; use small multiples. - avoid: Relying on the filled area to be readable at low opacity — check the fill against every theme's canvas. - RadarGrid - RadarLabels - RadarProvider - RADIAL_SEGMENTS - RadialGradient - RampLegend — The colour-scale key for a sequential or diverging chart: a continuous ramp with its low and high values. - RANGE_THUMB_TARGET - ReferenceLine - Ring - RingCenter - RingChart — A single value as a filled ring (a progress or share reading) with the number in the centre. - RingProvider - Ruler - SankeyChart — Flow diagram — how quantity moves between stages or nodes. - avoid: A Sankey for a simple two-column comparison — reach for a bar chart. - avoid: Raw colors on nodes/links — resolve the chart tokens so the dark theme reads correctly. - avoid: So many nodes that the labels collide — aggregate the tail into one 'other' node. - SankeyLink - SankeyNode - SankeyProvider - SankeyThreadLinks — SankeyChart mode="threads" per-record renderer — one polyline per row instead of one aggregate edge per node pair, for tracing an individual route (e.g. a shipment, a session) through several hops. - avoid: Using mode="threads" for a small, low-cardinality flow — that's what the default aggregate SankeyLink is for. - avoid: Supplying `path` names that don't match any `SankeyNodeDatum.name` — the route silently falls back to source/target only. - avoid: Making the visible thread path itself interactive — pointer handling belongs on the fat, transparent hit-twin so overlapping routes don't fight for clicks. - avoid: Relying on keyboard focus reaching inside the — the keyboard path is the sibling ChartDatapointLayer, never a focusable SVG element. - SankeyTooltip - Scatter - SCATTER_SHAPE_SOFT_CAP - ScatterChart — Point cloud for correlation between two continuous measures. - avoid: Connecting the points — a line asserts a sequence a scatter does not have. - avoid: Plotting tens of thousands of raw points — past ~20k use DensityScatterChart (every point drawn, density as colour); below that, bin or sample. - avoid: Distinguishing groups by colour only at default opacity — overlapping marks collapse; add shape or facets. - SegmentBackground - SegmentLineFrom - SegmentLineTo - SELECTED_OUTLINE_WIDTH - SELECTION_EXCLUDED_OPACITY - SERIES_LABEL_INK_MIX - SeriesBar - SeriesMarkers - SeriesPointMarker - SizeLegend - Sparkline — Tiny, axis-less trend that lives inside a KPI tile or a table cell. - avoid: Adding axes and tooltips to a Sparkline — if it needs them it is a LineChart. - avoid: A Sparkline as the only carrier of a number — pair it with the value (MetricCard). - avoid: Fixing its width in pixels — let the tile or cell own the box so it reflows. - StaticChartPreviewProvider - STRIP_MAX_ROWS_PER_GROUP - TIME_MIN_SPAN_STEPS - TreeChart — Fixed-spacing hierarchy diagram, left to right or top to bottom, drawn as dots or as your own same-size cards, whose branches open and close by default — no values, no sizes: ‘who belongs to whom’. - avoid: Reaching for TreeChart when the real question is 'how big is each part' — that is TreemapChart's job (leaf AREA proportional to value). A tree answers only 'what contains what'. - avoid: Encoding a value in node size or area — in a renderNode card too: every custom node is the same nodeWidth × nodeHeight box; put the number INSIDE the card as text and restate it through datapointLabel. - avoid: Putting buttons or links inside renderNode — the content is aria-hidden and inert; the chart owns the open/close pill and the keyboard tree, and onDatapointClick is the drill-in. - avoid: Expecting the layout to shrink to fit its container — it lays out at FIXED spacing and scrolls inside its box instead of compressing into illegibility. - avoid: Reaching for collapseDepth — it is deprecated: use defaultExpandedDepth (or expandedIds + onExpandedChange); only collapsible={false} keeps the static chart and its '+k' pill. - TREEMAP_BAND_COLOR - TREEMAP_CATEGORICAL_GROUP_CAP - TREEMAP_MAX_LEAVES - TREEMAP_MONO_LEAF_COLOR - TREEMAP_TITLE_BAND_HEIGHT - TreemapChart — Two-level squarified treemap — a hierarchy where area, not position, encodes value. - avoid: Comparing a leaf's area against a leaf in a different group — area is only comparable WITHIN one parent's total; two leaves under different groups are fractions of different denominators, so their tile sizes are not commensurate across the group boundary. - avoid: Reaching for palette: 'categorical' to encode a second measure on top of area — the hue there still only labels the group a leaf already belongs to (structurally, via the band); asking it to carry an unrelated variable makes one channel do two jobs and defeats the mono default's greyscale-legible design. - avoid: Leaving a long tail of small leaves unmerged until tiles fall below labelMinArea — set otherThreshold before that happens (the unconditional 30-leaf cap is a backstop, not a substitute for tuning it); a treemap of unlabeled slivers reads as noise, not a breakdown. - avoid: Turning on drilldown as the only way to reach a leaf's value — the group-band zoom button is a SEPARATE affordance from onDatapointClick on purpose; a leaf stays selectable by its own click/Enter without first forcing a reader to drill in. - TrendLine - UNIT_CHART_GROUP_STAGGER_MS - UNIT_CHART_POSITION_STAGGER_MS - UNIT_STACK_EMPHASIS - UnitChart — One mark = one honest unit — waffle grid, phyllotaxis field or tick rows, so a share is COUNTED rather than judged by angle or area; lieflat's default replacement for a pie. - avoid: Sizing a waffle or field past a few hundred marks in a small frame — one stack stops being countable past ~60 units and here that failure spans the WHOLE canvas, so budget total, columns and frame size together. - avoid: Turning showArithmetic off (or padding a count) because a rounded-away caption looks untidy — the caption exists BECAUSE the chart never invents a mark to hit total; hiding it trades the one honest-count promise this chart makes for a tidier footer. - avoid: Reaching for layout="field" when the reader needs to rank or compare series precisely — a phyllotaxis cluster reads as an area impression, not a countable structure; a real comparison wants rows or waffle. - avoid: Falling back to a pie chart because comparing shares 'still feels easier' — a slice angle cannot be counted, a mark can. If the categories don't sum to a meaningful whole, use the rows layout, not a pie. - UnitStack — n countable marks — rungs, ticks or dots — so a quantity is COUNTED rather than compared; the jitter is seeded, never random. - avoid: Passing a large n and calling it a bar — past roughly 60 units the stack stops being countable and becomes a texture, at which point a bar is the honest mark. It will happily draw 500; that is your judgment, not its. - avoid: Reaching for Math.random to jitter — use seededRnd. Random jitter makes the chart a different picture on every render, so no snapshot, visual-regression shot or play-function assertion can ever agree with itself. - avoid: Giving every stack the same seed — neighbouring stacks then jitter in lockstep and the irregularity reads as a pattern, which is worse than no jitter at all. Vary the seed per series or per row. - avoid: Turning markEvery off on a long stack — without the every-fifth cue the reader counts one by one, which is exactly the cost this mark was chosen to avoid. - WaterfallChart — Gross-to-net bridge: running-total steps and subtotal bars showing what added and subtracted along the way. - avoid: A `total` row whose value does not actually equal the running total at that point — the connector into it visibly plunges/jumps instead of landing flat, which is the bridge silently telling you the reconciliation is wrong. - avoid: Reading the dashed connector as if it carries a value — it is furniture that hands off between steps, never a series; the story is the bar heights, not the connector's slope. - avoid: Entering a reduction as a positive `value` (or otherwise fighting the sign convention) — color and the +/− label are derived from the actual before/after delta, not from caller intent, so a flipped sign silently mislabels the step. - avoid: More than ~6-8 steps in one bridge — past that the running total stops being followable and the connectors turn into visual noise; split into a top-level bridge plus a drill-down instead. - XAxis - Y_AXIS_DEFAULT_TICK_COUNT - Y_AXIS_MAX_TICK_COUNT - Y_AXIS_MIN_TICK_COUNT - YAxis ## Hooks - useActivateDatapoint - useActiveMarkers - useAnimatedYDomains - useCanvasDraw - useChart - useChartAnalytics - useChartAnnotationsA11y - useChartBreakpoint - useChartConfig - useChartDatapointsEnabled - useChartGesture - useChartGestureOverlay - useChartHover - useChartInteraction - useChartInteractionPolicy - useChartLegendHover - useChartSelectionGestureScope - useChartSelectionGesturesEnabled - useChartSelectionSession - useChartSeriesKey - useChartStable - useChartTooltipValueFormat - useChartValueSetFormatter - useChoropleth - useChoroplethZoom - useContainerLegend - useContainerSelection - useDensityView - useHeatmap - useHeatmapHover - useHighDecoration - useHighDecorationOf - useKeyboardRect - useLegend - useLegendItem - useMarkGeometry - useMarkGeometryStore - usePie - usePieHover - usePieStable - useProfitLossLegendHover - useRadar - useRadarHover - useRadarStable - useRangeSelect - useRegisterDatapointTargets - useRegisterMarkGeometry - useResolvedRadius - useResolvedRadiusOf - useResponsiveValue - useRing - useRingHover - useRingStable - useSankey - useSelectionDriver - useSelectionSession - useStaticChartPreview - useTooltipPin - useYScale