> ## Documentation Index
> Fetch the complete documentation index at: https://api.fanvue.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Chart

> The Recharts building blocks on @fanvue/ui/charts: ChartContainer and ChartStyle for theming, ChartTooltip, ChartLegend and ChartCard for the chrome, plus loading and skeleton states.

<Warning>
  This subpath needs the optional `recharts` peer dependency: `pnpm add recharts`.
  See [Subpath exports](/docs/ui/subpath-exports).
</Warning>

```tsx theme={null}
import {
  ChartCard,
  ChartCenterLabel,
  ChartContainer,
  ChartLegend,
  ChartLegendContent,
  ChartLoadingOverlay,
  ChartMetricTrend,
  ChartPieLegend,
  ChartSeriesToggle,
  ChartSkeleton,
  ChartStyle,
  ChartTooltip,
  ChartTooltipContent,
  resolveConfigEntry,
  useChart,
} from "@fanvue/ui/charts";
import type {
  ChartCardProps,
  ChartCenterLabelProps,
  ChartConfig,
  ChartConfigEntry,
  ChartContainerProps,
  ChartLegendContentProps,
  ChartLoadingOverlayProps,
  ChartMetricTrendColor,
  ChartMetricTrendProps,
  ChartPieLegendItem,
  ChartPieLegendProps,
  ChartSeriesToggleItem,
  ChartSeriesToggleProps,
  ChartSkeletonProps,
  ChartSkeletonVariant,
  ChartStyleProps,
  ChartThemeKey,
  ChartTooltipContentProps,
  ChartTooltipIndicator,
} from "@fanvue/ui/charts";
```

## Examples

## AreaChart — Default

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-charts-areachart--default&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="360" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="AreaChart — Default" />
</Frame>

```tsx theme={null}
import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@fanvue/ui/charts";
import type { ChartConfig } from "@fanvue/ui/charts";
import { Area, AreaChart, CartesianGrid, XAxis } from "recharts";

const earningsData = [
  { month: "Jan", earnings: 2400 },
  { month: "Feb", earnings: 1398 },
  { month: "Mar", earnings: 3200 },
  { month: "Apr", earnings: 2780 },
  { month: "May", earnings: 4890 },
  { month: "Jun", earnings: 3908 },
];

function AreaGradient({ id, color }: { id: string; color: string }) {
  return (
    <linearGradient id={id} x1="0" y1="0" x2="0" y2="1">
      <stop offset="5%" stopColor={color} stopOpacity={0.8} />
      <stop offset="95%" stopColor={color} stopOpacity={0.1} />
    </linearGradient>
  );
}

const earningsConfig = {
  earnings: { label: "Earnings", color: "var(--color-special-chart-teal)" },
} satisfies ChartConfig;

<ChartContainer config={earningsConfig} className="min-h-[200px] w-full max-w-lg">
  <AreaChart accessibilityLayer data={earningsData}>
    <defs>
      <AreaGradient id="fillEarnings" color="var(--color-earnings)" />
    </defs>
    <CartesianGrid vertical={false} />
    <XAxis dataKey="month" tickLine={false} axisLine={false} tickMargin={8} />
    <ChartTooltip content={<ChartTooltipContent />} />
    <Area
      type="natural"
      dataKey="earnings"
      stroke="var(--color-earnings)"
      fill="url(#fillEarnings)"
    />
  </AreaChart>
</ChartContainer>
```

## AreaChart — With Legend

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-charts-areachart--with-legend&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="360" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="AreaChart — With Legend" />
</Frame>

```tsx theme={null}
import {
  ChartContainer,
  ChartLegend,
  ChartLegendContent,
  ChartTooltip,
  ChartTooltipContent,
} from "@fanvue/ui/charts";
import type { ChartConfig } from "@fanvue/ui/charts";
import { Area, AreaChart, CartesianGrid, XAxis } from "recharts";

const visitorsData = [
  { month: "Jan", desktop: 1860, mobile: 1200 },
  { month: "Feb", desktop: 2105, mobile: 1450 },
  { month: "Mar", desktop: 2370, mobile: 1680 },
  { month: "Apr", desktop: 1730, mobile: 1900 },
  { month: "May", desktop: 2490, mobile: 2100 },
  { month: "Jun", desktop: 2140, mobile: 2450 },
];

const visitorsConfig = {
  desktop: {
    label: "Desktop",
    color: "var(--color-special-chart-sky)",
  },
  mobile: {
    label: "Mobile",
    color: "var(--color-special-chart-magenta)",
  },
} satisfies ChartConfig;

function VisitorsAreaChart({ showLegend = false }: { showLegend?: boolean }) {
  return (
    <ChartContainer config={visitorsConfig} className="min-h-[200px] w-full max-w-lg">
      <AreaChart accessibilityLayer data={visitorsData}>
        <defs>
          <AreaGradient id="fillDesktop" color="var(--color-desktop)" />
          <AreaGradient id="fillMobile" color="var(--color-mobile)" />
        </defs>
        <CartesianGrid vertical={false} />
        <XAxis dataKey="month" tickLine={false} axisLine={false} tickMargin={8} />
        <ChartTooltip content={<ChartTooltipContent />} />
        {showLegend && <ChartLegend content={<ChartLegendContent />} />}
        <Area
          type="natural"
          dataKey="desktop"
          stroke="var(--color-desktop)"
          fill="url(#fillDesktop)"
        />
        <Area
          type="natural"
          dataKey="mobile"
          stroke="var(--color-mobile)"
          fill="url(#fillMobile)"
        />
      </AreaChart>
    </ChartContainer>
  );
}

function AreaGradient({ id, color }: { id: string; color: string }) {
  return (
    <linearGradient id={id} x1="0" y1="0" x2="0" y2="1">
      <stop offset="5%" stopColor={color} stopOpacity={0.8} />
      <stop offset="95%" stopColor={color} stopOpacity={0.1} />
    </linearGradient>
  );
}

<VisitorsAreaChart showLegend />
```

## AreaChart — Stacked

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-charts-areachart--stacked&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="360" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="AreaChart — Stacked" />
</Frame>

```tsx theme={null}
import {
  ChartContainer,
  ChartLegend,
  ChartLegendContent,
  ChartTooltip,
  ChartTooltipContent,
} from "@fanvue/ui/charts";
import type { ChartConfig } from "@fanvue/ui/charts";
import { Area, AreaChart, CartesianGrid, XAxis } from "recharts";

const visitorsData = [
  { month: "Jan", desktop: 1860, mobile: 1200 },
  { month: "Feb", desktop: 2105, mobile: 1450 },
  { month: "Mar", desktop: 2370, mobile: 1680 },
  { month: "Apr", desktop: 1730, mobile: 1900 },
  { month: "May", desktop: 2490, mobile: 2100 },
  { month: "Jun", desktop: 2140, mobile: 2450 },
];

const visitorsConfig = {
  desktop: {
    label: "Desktop",
    color: "var(--color-special-chart-sky)",
  },
  mobile: {
    label: "Mobile",
    color: "var(--color-special-chart-magenta)",
  },
} satisfies ChartConfig;

function VisitorsAreaChart({ showLegend = false }: { showLegend?: boolean }) {
  return (
    <ChartContainer config={visitorsConfig} className="min-h-[200px] w-full max-w-lg">
      <AreaChart accessibilityLayer data={visitorsData}>
        <defs>
          <AreaGradient id="fillDesktop" color="var(--color-desktop)" />
          <AreaGradient id="fillMobile" color="var(--color-mobile)" />
        </defs>
        <CartesianGrid vertical={false} />
        <XAxis dataKey="month" tickLine={false} axisLine={false} tickMargin={8} />
        <ChartTooltip content={<ChartTooltipContent />} />
        {showLegend && <ChartLegend content={<ChartLegendContent />} />}
        <Area
          type="natural"
          dataKey="desktop"
          stroke="var(--color-desktop)"
          fill="url(#fillDesktop)"
        />
        <Area
          type="natural"
          dataKey="mobile"
          stroke="var(--color-mobile)"
          fill="url(#fillMobile)"
        />
      </AreaChart>
    </ChartContainer>
  );
}

function AreaGradient({ id, color }: { id: string; color: string }) {
  return (
    <linearGradient id={id} x1="0" y1="0" x2="0" y2="1">
      <stop offset="5%" stopColor={color} stopOpacity={0.8} />
      <stop offset="95%" stopColor={color} stopOpacity={0.1} />
    </linearGradient>
  );
}

<VisitorsAreaChart />
```

## AreaChart — Multi Series

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-charts-areachart--multi-series&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="360" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="AreaChart — Multi Series" />
</Frame>

```tsx theme={null}
import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@fanvue/ui/charts";
import type { ChartConfig } from "@fanvue/ui/charts";
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from "recharts";

const multiSeriesData = [
  { month: "Jan", revenue: 4200, expenses: 2800, profit: 1400 },
  { month: "Feb", revenue: 3800, expenses: 2600, profit: 1200 },
  { month: "Mar", revenue: 5100, expenses: 3200, profit: 1900 },
  { month: "Apr", revenue: 4600, expenses: 3000, profit: 1600 },
  { month: "May", revenue: 5800, expenses: 3400, profit: 2400 },
  { month: "Jun", revenue: 6200, expenses: 3600, profit: 2600 },
  { month: "Jul", revenue: 5400, expenses: 3100, profit: 2300 },
  { month: "Aug", revenue: 6800, expenses: 3800, profit: 3000 },
];

const multiSeriesConfig = {
  revenue: {
    label: "Revenue",
    color: "var(--color-special-chart-teal)",
  },
  expenses: {
    label: "Expenses",
    color: "var(--color-special-chart-pink)",
  },
  profit: {
    label: "Profit",
    color: "var(--color-special-chart-sky)",
  },
} satisfies ChartConfig;

function AreaGradient({ id, color }: { id: string; color: string }) {
  return (
    <linearGradient id={id} x1="0" y1="0" x2="0" y2="1">
      <stop offset="5%" stopColor={color} stopOpacity={0.8} />
      <stop offset="95%" stopColor={color} stopOpacity={0.1} />
    </linearGradient>
  );
}

<ChartContainer config={multiSeriesConfig} className="min-h-[200px] w-full max-w-lg">
  <AreaChart accessibilityLayer data={multiSeriesData}>
    <defs>
      <AreaGradient id="fillRevenue" color="var(--color-revenue)" />
      <AreaGradient id="fillExpenses" color="var(--color-expenses)" />
      <AreaGradient id="fillProfit" color="var(--color-profit)" />
    </defs>
    <CartesianGrid vertical={false} />
    <XAxis dataKey="month" tickLine={false} axisLine={false} tickMargin={8} />
    <YAxis tickLine={false} axisLine={false} tickMargin={8} />
    <ChartTooltip content={<ChartTooltipContent />} />
    <Area
      type="natural"
      dataKey="revenue"
      stroke="var(--color-revenue)"
      fill="url(#fillRevenue)"
    />
    <Area
      type="natural"
      dataKey="expenses"
      stroke="var(--color-expenses)"
      fill="url(#fillExpenses)"
    />
    <Area
      type="natural"
      dataKey="profit"
      stroke="var(--color-profit)"
      fill="url(#fillProfit)"
    />
  </AreaChart>
</ChartContainer>
```

## AreaChart — Linear

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-charts-areachart--linear&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="360" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="AreaChart — Linear" />
</Frame>

```tsx theme={null}
import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@fanvue/ui/charts";
import type { ChartConfig } from "@fanvue/ui/charts";
import { Area, AreaChart, CartesianGrid, XAxis } from "recharts";

const linearData = [
  { month: "Jan", value: 1200 },
  { month: "Feb", value: 1800 },
  { month: "Mar", value: 1400 },
  { month: "Apr", value: 2600 },
  { month: "May", value: 2200 },
  { month: "Jun", value: 3100 },
];

const linearConfig = {
  value: {
    label: "Value",
    color: "var(--color-special-chart-orange)",
  },
} satisfies ChartConfig;

function AreaGradient({ id, color }: { id: string; color: string }) {
  return (
    <linearGradient id={id} x1="0" y1="0" x2="0" y2="1">
      <stop offset="5%" stopColor={color} stopOpacity={0.8} />
      <stop offset="95%" stopColor={color} stopOpacity={0.1} />
    </linearGradient>
  );
}

<ChartContainer config={linearConfig} className="min-h-[200px] w-full max-w-lg">
  <AreaChart accessibilityLayer data={linearData}>
    <defs>
      <AreaGradient id="fillLinear" color="var(--color-value)" />
    </defs>
    <CartesianGrid vertical={false} />
    <XAxis dataKey="month" tickLine={false} axisLine={false} tickMargin={8} />
    <ChartTooltip content={<ChartTooltipContent />} />
    <Area type="linear" dataKey="value" stroke="var(--color-value)" fill="url(#fillLinear)" />
  </AreaChart>
</ChartContainer>
```

## BarChart — Default

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-charts-barchart--default&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="360" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="BarChart — Default" />
</Frame>

```tsx theme={null}
import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@fanvue/ui/charts";
import type { ChartConfig } from "@fanvue/ui/charts";
import { Bar, BarChart, CartesianGrid, XAxis } from "recharts";

const earningsData = [
  { category: "Photos", earnings: 4200 },
  { category: "Videos", earnings: 7800 },
  { category: "Messages", earnings: 3100 },
  { category: "Tips", earnings: 5400 },
  { category: "Streams", earnings: 6200 },
  { category: "Bundles", earnings: 2900 },
];

function EarningsBarChart({
  radius = [8, 8, 0, 0],
}: {
  radius?: [number, number, number, number];
}) {
  return (
    <ChartContainer config={earningsConfig} className="min-h-[200px] w-full max-w-lg">
      <BarChart accessibilityLayer data={earningsData}>
        <CartesianGrid vertical={false} />
        <XAxis dataKey="category" tickLine={false} axisLine={false} tickMargin={8} />
        <ChartTooltip content={<ChartTooltipContent />} />
        <Bar dataKey="earnings" fill="var(--color-earnings)" radius={radius} />
      </BarChart>
    </ChartContainer>
  );
}

const earningsConfig = {
  earnings: { label: "Earnings", color: "var(--color-special-chart-teal)" },
} satisfies ChartConfig;

<EarningsBarChart />
```

## BarChart — Negative Values

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-charts-barchart--negative-values&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="360" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="BarChart — Negative Values" />
</Frame>

```tsx theme={null}
import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@fanvue/ui/charts";
import type { ChartConfig } from "@fanvue/ui/charts";
import { Bar, BarChart, CartesianGrid, Cell, XAxis } from "recharts";

const negativeData = [
  { month: "Jan", change: 1200 },
  { month: "Feb", change: -400 },
  { month: "Mar", change: 800 },
  { month: "Apr", change: -150 },
  { month: "May", change: 2100 },
  { month: "Jun", change: -600 },
  { month: "Jul", change: 1500 },
  { month: "Aug", change: -300 },
];

const negativeConfig = {
  change: {
    label: "Net Change",
    color: "var(--color-special-chart-teal)",
  },
} satisfies ChartConfig;

<ChartContainer config={negativeConfig} className="min-h-[200px] w-full max-w-lg">
  <BarChart accessibilityLayer data={negativeData}>
    <CartesianGrid vertical={false} />
    <XAxis dataKey="month" tickLine={false} axisLine={false} tickMargin={8} />
    <ChartTooltip content={<ChartTooltipContent />} />
    <Bar dataKey="change" radius={[8, 8, 0, 0]}>
      {negativeData.map((entry) => (
        <Cell
          key={entry.month}
          fill={
            entry.change >= 0
              ? "var(--color-special-chart-teal)"
              : "var(--color-special-chart-pink)"
          }
        />
      ))}
    </Bar>
  </BarChart>
</ChartContainer>
```

## BarChart — With Legend

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-charts-barchart--with-legend&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="360" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="BarChart — With Legend" />
</Frame>

```tsx theme={null}
import {
  ChartContainer,
  ChartLegend,
  ChartLegendContent,
  ChartTooltip,
  ChartTooltipContent,
} from "@fanvue/ui/charts";
import type { ChartConfig } from "@fanvue/ui/charts";
import { Bar, BarChart, CartesianGrid, XAxis } from "recharts";

const legendData = [
  { month: "Jan", subscribers: 320, followers: 1200 },
  { month: "Feb", subscribers: 380, followers: 1450 },
  { month: "Mar", subscribers: 410, followers: 1600 },
  { month: "Apr", subscribers: 450, followers: 1850 },
  { month: "May", subscribers: 520, followers: 2100 },
  { month: "Jun", subscribers: 580, followers: 2400 },
  { month: "Jul", subscribers: 640, followers: 2800 },
];

const legendConfig = {
  subscribers: {
    label: "Subscribers",
    color: "var(--color-special-chart-purple)",
  },
  followers: {
    label: "Followers",
    color: "var(--color-special-chart-orange)",
  },
} satisfies ChartConfig;

<ChartContainer config={legendConfig} className="min-h-[200px] w-full max-w-lg">
  <BarChart accessibilityLayer data={legendData}>
    <CartesianGrid vertical={false} />
    <XAxis dataKey="month" tickLine={false} axisLine={false} tickMargin={8} />
    <ChartTooltip content={<ChartTooltipContent />} />
    <ChartLegend content={<ChartLegendContent />} />
    <Bar dataKey="subscribers" fill="var(--color-subscribers)" radius={[8, 8, 0, 0]} />
    <Bar dataKey="followers" fill="var(--color-followers)" radius={[8, 8, 0, 0]} />
  </BarChart>
</ChartContainer>
```

## Props

## ChartCard

Wraps any chart with a structured header containing title, subtitle, optional trend indicator, date range label, info tooltip, and a loading skeleton state.

At `hierarchy="primary"` this implements the V2 Insight Card surface, which differs from `Card`'s own primary hierarchy: a white fill, the strong border, and a 12px radius.

<ParamField path="title" type="ReactNode" required>
  Card title text. Pass translated string for i18n.
</ParamField>

<ParamField path="children" type="ReactNode">
  Chart content rendered below the header.
</ParamField>

<ParamField path="dateInfo" type="ReactNode">
  Date range or period label shown below the subtitle.
</ParamField>

<ParamField path="hierarchy" type="&#x22;primary&#x22; | &#x22;secondary&#x22;" default="primary">
  Surface treatment. `primary` follows the V2 Insight Card spec (white fill, strong border, 12px radius); `secondary` uses the `Card` secondary surface.
</ParamField>

<ParamField path="loading" type="boolean" default="false">
  Show loading skeleton instead of content.
</ParamField>

<ParamField path="subtitle" type="ReactNode">
  Large subtitle value (e.g. formatted price or count).
</ParamField>

<ParamField path="tooltip" type="ReactNode">
  Tooltip text shown next to the title. Pass translated string for i18n.
</ParamField>

<ParamField path="tooltipAriaLabel" type="string" default="More info">
  Accessible label for the info tooltip trigger. Override for i18n.
</ParamField>

<ParamField path="trendChip" type="{ label: ReactNode; trend: &#x22;negative&#x22; | &#x22;positive&#x22;; }">
  Trend indicator config. Rendered as a coloured directional arrow and label beside the subtitle, so it is only shown when `subtitle` is provided.
</ParamField>

## ChartCenterLabel

Centered label for radial/pie charts, rendered inside a Recharts `<Label>`.

<ParamField path="subtitle" type="ReactNode" required>
  Secondary text below the value.
</ParamField>

<ParamField path="value" type="ReactNode" required>
  Primary value displayed in the center.
</ParamField>

<ParamField path="valueClassName" type="string" default="fill-content-primary font-bold text-3xl">
  Custom className for the value tspan.
</ParamField>

<ParamField path="viewBox" type="{ [key: string]: unknown; cx?: number; cy?: number; } | undefined">
  Recharts viewBox with center coordinates.
</ParamField>

## ChartContainer

Wraps a Recharts chart with responsive sizing, design-token theming, and accessible config context for tooltips and legends.

<ParamField path="children" type="ReactNode" required>
  Recharts chart element(s) to render inside the responsive container. Typically a single `<AreaChart>`, `<BarChart>`, `<LineChart>`, etc.
</ParamField>

<ParamField path="config" type="ChartConfig" required>
  Series configuration mapping data keys to labels, colors, and icons.
</ParamField>

## ChartLegend

Re-export of Recharts `Legend` — use with `content={<ChartLegendContent />}`.

A direct re-export of `RechartsLegend` from `recharts`, provided so a chart can be assembled from one import. Its props are recharts's own — see the [recharts documentation](https://www.npmjs.com/package/recharts).

## ChartLegendContent

Styled legend content for use with `<ChartLegend content={<ChartLegendContent />} />`.

Reads chart config from context to resolve labels and icons.

<ParamField path="hideIcon" type="boolean" default="false">
  Hide the color/icon indicator.
</ParamField>

<ParamField path="nameKey" type="string">
  Data key used to resolve the display name from config.
</ParamField>

<ParamField path="payload" type="readonly LegendPayload[]">
  Legend payload data. Passed by Recharts.
</ParamField>

<ParamField path="verticalAlign" type="&#x22;top&#x22; | &#x22;bottom&#x22;" default="bottom">
  Vertical alignment — controls padding direction.
</ParamField>

## ChartLoadingOverlay

A positioned overlay shown on top of chart content while it loads. The children are always rendered to maintain layout dimensions.

By default the overlay is opaque and shows a wave-animated `ChartSkeleton` shaped like the chart. At `variant={false}` it falls back to a semi-transparent wash with a centred spinner.

<ParamField path="children" type="ReactNode" required>
  Chart content to render underneath the overlay.
</ParamField>

<ParamField path="loading" type="boolean" default="false">
  Whether to show the loading overlay.
</ParamField>

<ParamField path="loadingLabel" type="string" default="Loading chart">
  Accessible name for the loading region, announced while `loading` is true. Pass a translated string for i18n. Only applies to the skeleton path; the `variant={false}` spinner carries its own label.
</ParamField>

<ParamField path="variant" type="false | ChartSkeletonVariant" default="area">
  Shape of the wave-animated `ChartSkeleton` shown while loading. Set it to match the chart underneath — `circular` for pie/radial, `bar` for bar charts. Pass `false` to fall back to the legacy centred spinner.
</ParamField>

## ChartMetricTrend

The small area chart inside a metric tile, per the `V2 Area Chart Item` slot of the Figma insight card.

`series` is optional because the endpoints behind these cards often return a single scalar with no history. With nothing to plot the chart draws a flat line at the current value rather than collapsing the slot, so the card keeps the height and shape the design gives it. The line is deliberately level rather than shaped, so it asserts no history that the data cannot support.

<ParamField path="color" type="&#x22;red&#x22; | &#x22;teal&#x22;" required>
  Gradient and stroke colour.
</ParamField>

<ParamField path="value" type="number" required>
  Current value. Also the flat-line height when `series` is absent.
</ParamField>

<ParamField path="series" type="number[]">
  History to plot. Needs more than one point to draw a shape.
</ParamField>

## ChartPieLegend

A side legend for pie/donut charts that shows each slice's label, formatted value, and a proportional progress bar.

<ParamField path="items" type="ChartPieLegendItem[]" required>
  Legend items to display.
</ParamField>

## ChartSeriesToggle

Renders a wrapping row of toggleable `Chip`s that control which series are visible on a multi-series chart. Each chip sizes to its label, shows a series colour dot, and exposes its state through `aria-pressed`.

<ParamField path="items" type="ChartSeriesToggleItem[]" required>
  Available series that can be toggled.
</ParamField>

<ParamField path="onValueChange" type="(value: Set<string>) => void" required>
  Called when a series is toggled. Receives the updated Set.
</ParamField>

<ParamField path="value" type="Set<string>" required>
  Set of currently visible series keys.
</ParamField>

## ChartSkeleton

A wave-animated placeholder shaped like the content it stands in for — a chart series, a ranked table, or a breakdown of labelled bars. Use it while data loads instead of a generic spinner, so the layout does not visibly shift once the real content renders.

For a chart body, pass it to `ChartLoadingOverlay` via its `variant` prop rather than rendering it directly. For a card body, pass it to `ChartCard`'s `skeleton` prop.

<ParamField path="rows" type="number">
  How many items to draw: rows for `table` and `rows`, bars for `bar`. Match the count the loaded card will show, so the card does not resize once the real content arrives. Defaults to 5 rows, or 7 bars.
</ParamField>

<ParamField path="variant" type="&#x22;area&#x22; | &#x22;table&#x22; | &#x22;line&#x22; | &#x22;bar&#x22; | &#x22;circular&#x22; | &#x22;rows&#x22;" default="area">
  Which shape to imitate.
</ParamField>

## ChartStyle

Injects a scoped `<style>` tag that maps each config entry to a `--color-{key}` CSS custom property, with light/dark theme support.

Rendered automatically by `ChartContainer` — you rarely need this directly.

<ParamField path="config" type="ChartConfig" required>
  Chart configuration mapping data keys to colors and themes.
</ParamField>

<ParamField path="id" type="string" required>
  Unique identifier scoped to the chart instance.
</ParamField>

## ChartTooltip

Re-export of Recharts `Tooltip` — use with `content={<ChartTooltipContent />}`.

A direct re-export of `RechartsTooltip` from `recharts`, provided so a chart can be assembled from one import. Its props are recharts's own — see the [recharts documentation](https://www.npmjs.com/package/recharts).

## ChartTooltipContent

Styled tooltip content for use with `<ChartTooltip content={<ChartTooltipContent />} />`.

Reads chart config from context to resolve labels, colors, and icons. Supports dot/line/dashed indicators. Pass translated `label`s in config for i18n.

<ParamField path="active" type="boolean">
  Whether the tooltip is currently active/visible. Passed by Recharts.
</ParamField>

<ParamField path="color" type="string">
  Override indicator color for all rows.
</ParamField>

<ParamField path="formatter" type="((value: ValueType, name: NameType, item: Payload<ValueType, NameType>, index: number, ...">
  Custom value formatter.

  Full type: `((value: ValueType, name: NameType, item: Payload<ValueType, NameType>, index: number, payload: Payload<ValueType, NameType>[]) => ReactNode)`.
</ParamField>

<ParamField path="hideIndicator" type="boolean" default="false">
  Hide the color indicator beside each row.
</ParamField>

<ParamField path="hideLabel" type="boolean" default="false">
  Hide the tooltip header label.
</ParamField>

<ParamField path="indicator" type="&#x22;line&#x22; | &#x22;dot&#x22; | &#x22;dashed&#x22;" default="dot">
  Visual style of the color indicator.
</ParamField>

<ParamField path="label" type="string | number">
  Axis label. Passed by Recharts.
</ParamField>

<ParamField path="labelClassName" type="string">
  CSS class for the label element.
</ParamField>

<ParamField path="labelFormatter" type="((label: string | number, payload: Payload<ValueType, NameType>[]) => ReactNode)">
  Custom label formatter.
</ParamField>

<ParamField path="labelKey" type="string">
  Data key used to resolve the header label from config. Falls back to the first payload item's `dataKey`.
</ParamField>

<ParamField path="nameKey" type="string">
  Data key used to resolve the display name from config. Useful when the payload `name` differs from the config key.
</ParamField>

<ParamField path="payload" type="Payload<ValueType, NameType>[]">
  Tooltip payload data. Passed by Recharts.
</ParamField>

## resolveConfigEntry

Resolves the `ChartConfig` entry for a given tooltip/legend payload item. Recharts wraps the original data point inside `payload.payload` — this function checks both levels before falling back to a direct `key` lookup.

Takes no props of its own beyond the standard attributes of the element it renders.

## useChart

Access the nearest `ChartContainer`'s config. Throws if used outside a chart.

Takes no props of its own beyond the standard attributes of the element it renders.

## Exported types

Also exported from `@fanvue/ui/charts`: `ChartCardProps`, `ChartCenterLabelProps`, `ChartConfig`, `ChartConfigEntry`, `ChartContainerProps`, `ChartLegendContentProps`, `ChartLoadingOverlayProps`, `ChartMetricTrendColor`, `ChartMetricTrendProps`, `ChartPieLegendItem`, `ChartPieLegendProps`, `ChartSeriesToggleItem`, `ChartSeriesToggleProps`, `ChartSkeletonProps`, `ChartSkeletonVariant`, `ChartStyleProps`, `ChartThemeKey`, `ChartTooltipContentProps`, `ChartTooltipIndicator`.

***

**Setup:** [Installation](/docs/ui/installation) · [Theming](/docs/ui/theming) · [Subpath exports](/docs/ui/subpath-exports)
