HextaUI

Chart

Gráficos de Recharts con colores del tema, un tooltip y una leyenda que leen las etiquetas de una sola configuración, y navegación con teclado con un anillo de foco visible.

Visitors
Desktop and mobile visits per day
"use client"

import * as React from "react"
import { Area, AreaChart, CartesianGrid, XAxis } from "recharts"

import {
  Card,
  CardAction,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"
import {
  ChartContainer,
  ChartLegend,
  ChartLegendContent,
  ChartTooltip,
  ChartTooltipContent,
  type ChartConfig,
} from "@/components/ui/chart"
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"

const chartData = Array.from({ length: 90 }, (_, index) => {
  const date = new Date(Date.UTC(2026, 3, 1 + index))
  const wave = Math.sin(index / 6) * 60 + Math.sin(index / 2.3) * 25
  return {
    date: date.toISOString().slice(0, 10),
    desktop: Math.round(260 + wave + index * 1.6),
    mobile: Math.round(180 - wave * 0.6 + index * 1.1),
  }
})

const chartConfig = {
  desktop: {
    label: "Desktop",
    color: "var(--chart-1)",
  },
  mobile: {
    label: "Mobile",
    color: "var(--chart-2)",
  },
} satisfies ChartConfig

const ranges = [
  { value: "90", label: "90d", name: "Last 90 days" },
  { value: "30", label: "30d", name: "Last 30 days" },
  { value: "7", label: "7d", name: "Last 7 days" },
]

const dateFormat = new Intl.DateTimeFormat("en-US", {
  month: "short",
  day: "numeric",
  timeZone: "UTC",
})

function formatDate(value: unknown) {
  return dateFormat.format(new Date(`${value}T00:00:00Z`))
}

export function ChartDemo() {
  const [range, setRange] = React.useState("90")
  const data = chartData.slice(-Number(range))

  return (
    <Card className="w-full">
      <CardHeader>
        <CardTitle>Visitors</CardTitle>
        <CardDescription>Desktop and mobile visits per day</CardDescription>
        <CardAction>
          <ToggleGroup
            variant="outline"
            size="sm"
            aria-label="Time range"
            value={[range]}
            onValueChange={(value) => {
              if (value.length > 0) {
                setRange(value[0])
              }
            }}
          >
            {ranges.map((item) => (
              <ToggleGroupItem
                key={item.value}
                value={item.value}
                aria-label={item.name}
              >
                {item.label}
              </ToggleGroupItem>
            ))}
          </ToggleGroup>
        </CardAction>
      </CardHeader>
      <CardContent>
        <ChartContainer
          aria-label="Area chart of desktop and mobile visitors per day"
          config={chartConfig}
          className="h-64 w-full"
        >
          <AreaChart data={data} margin={{ left: 12, right: 12 }}>
            <defs>
              <linearGradient id="fill-desktop" x1="0" y1="0" x2="0" y2="1">
                <stop
                  offset="5%"
                  stopColor="var(--color-desktop)"
                  stopOpacity={0.3}
                />
                <stop
                  offset="95%"
                  stopColor="var(--color-desktop)"
                  stopOpacity={0.02}
                />
              </linearGradient>
              <linearGradient id="fill-mobile" x1="0" y1="0" x2="0" y2="1">
                <stop
                  offset="5%"
                  stopColor="var(--color-mobile)"
                  stopOpacity={0.3}
                />
                <stop
                  offset="95%"
                  stopColor="var(--color-mobile)"
                  stopOpacity={0.02}
                />
              </linearGradient>
            </defs>
            <CartesianGrid vertical={false} />
            <XAxis
              dataKey="date"
              tickLine={false}
              axisLine={false}
              tickMargin={8}
              minTickGap={32}
              tickFormatter={formatDate}
            />
            <ChartTooltip
              cursor={false}
              content={
                <ChartTooltipContent
                  indicator="dot"
                  labelFormatter={formatDate}
                />
              }
            />
            <Area
              dataKey="mobile"
              type="natural"
              fill="url(#fill-mobile)"
              stroke="var(--color-mobile)"
              strokeWidth={2}
              stackId="a"
            />
            <Area
              dataKey="desktop"
              type="natural"
              fill="url(#fill-desktop)"
              stroke="var(--color-desktop)"
              strokeWidth={2}
              stackId="a"
            />
            <ChartLegend content={<ChartLegendContent />} />
          </AreaChart>
        </ChartContainer>
      </CardContent>
    </Card>
  )
}
pnpm dlx shadcn@latest add https://hextaui.com/r/chart.json

Añade el componente, los tokens del tema de HextaUI y los componentes de HextaUI de los que depende.

Construyes los gráficos con componentes de Recharts y añades las partes de chart solo donde las necesitas. Recharts no está envuelto, así que su propia documentación y sus guías de actualización se aplican tal cual.

import { Bar, BarChart, CartesianGrid, XAxis } from "recharts"

import {
  ChartContainer,
  ChartLegend,
  ChartLegendContent,
  ChartTooltip,
  ChartTooltipContent,
  type ChartConfig,
} from "@/components/ui/chart"

Un ChartConfig asigna a cada clave de datos una etiqueta, un icono opcional y un color. Permanece separado de los datos, así que una misma config puede servir a varios gráficos.

const chartConfig = {
  desktop: {
    label: "Desktop",
    color: "var(--chart-1)",
  },
  mobile: {
    label: "Mobile",
    color: "var(--chart-2)",
  },
} satisfies ChartConfig
<ChartContainer
  aria-label="Bar chart of desktop and mobile visitors by month"
  config={chartConfig}
  className="min-h-52 w-full"
>
  <BarChart data={chartData}>
    <CartesianGrid vertical={false} />
    <XAxis dataKey="month" tickLine={false} axisLine={false} />
    <ChartTooltip content={<ChartTooltipContent />} />
    <ChartLegend content={<ChartLegendContent />} />
    <Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
    <Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
  </BarChart>
</ChartContainer>

Dale a <ChartContainer /> una altura, un min-h-* o un aspect-* para que el gráfico pueda medirse a sí mismo en el primer renderizado. Sin uno, recurre a aspect-video.

ChartContainer
└── BarChart / LineChart / AreaChart / …
    ├── ChartTooltip
    │   └── ChartTooltipContent
    └── ChartLegend
        └── ChartLegendContent

Cada clave de la config se convierte en una variable --color-KEY con alcance limitado a su gráfico. Apúntala a un token del tema, a cualquier color CSS, o dale valores light y dark por separado.

const chartConfig = {
  desktop: {
    label: "Desktop",
    icon: IconDeviceDesktop,
    color: "var(--chart-1)",
  },
  mobile: {
    label: "Mobile",
    theme: {
      light: "oklch(0.5 0.17 285)",
      dark: "oklch(0.75 0.14 190)",
    },
  },
} satisfies ChartConfig

Usa la variable donde Recharts acepte un color: en componentes, en tus datos o en clases de Tailwind.

<Bar dataKey="desktop" fill="var(--color-desktop)" />

const chartData = [
  { browser: "chrome", visitors: 275, fill: "var(--color-chrome)" },
]

<LabelList className="fill-(--color-desktop)" />

El tema incluye cinco tokens de gráfico, --chart-1 a --chart-5: azul, verde azulado, ámbar, violeta y rosa. En este orden, los colores vecinos se distinguen con las formas comunes de daltonismo, y cada uno tiene al menos un contraste de 3:1 con los fondos claro y oscuro. Úsalos en orden y mantén la leyenda o las etiquetas activadas, para que el color nunca sea la única pista.

Las claves que no son válidas en un nombre CSS, como Mobile users, se convierten en --color-Mobile-users.

Gráfico de barras

Una cuadrícula, un eje, <ChartTooltip /> y <ChartLegend />. El tooltip y la leyenda leen sus etiquetas y colores de la config.

"use client"

import { Bar, BarChart, CartesianGrid, XAxis } from "recharts"

import {
  ChartContainer,
  ChartLegend,
  ChartLegendContent,
  ChartTooltip,
  ChartTooltipContent,
  type ChartConfig,
} from "@/components/ui/chart"

const chartData = [
  { month: "January", desktop: 186, mobile: 80 },
  { month: "February", desktop: 305, mobile: 200 },
  { month: "March", desktop: 237, mobile: 120 },
  { month: "April", desktop: 73, mobile: 190 },
  { month: "May", desktop: 209, mobile: 130 },
  { month: "June", desktop: 214, mobile: 140 },
]

const chartConfig = {
  desktop: {
    label: "Desktop",
    color: "var(--chart-1)",
  },
  mobile: {
    label: "Mobile",
    color: "var(--chart-2)",
  },
} satisfies ChartConfig

export function ChartBar() {
  return (
    <ChartContainer
      aria-label="Bar chart of desktop and mobile visitors by month"
      config={chartConfig}
      className="min-h-52 w-full"
    >
      <BarChart data={chartData}>
        <CartesianGrid vertical={false} />
        <XAxis
          dataKey="month"
          tickLine={false}
          tickMargin={10}
          axisLine={false}
          tickFormatter={(value) => value.slice(0, 3)}
        />
        <ChartTooltip content={<ChartTooltipContent />} />
        <ChartLegend content={<ChartLegendContent />} />
        <Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
        <Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
      </BarChart>
    </ChartContainer>
  )
}

Gráfico de líneas

indicator="line" hace coincidir las claves del tooltip con las líneas que describen.

"use client"

import { CartesianGrid, Line, LineChart, XAxis, YAxis } from "recharts"

import {
  ChartContainer,
  ChartLegend,
  ChartLegendContent,
  ChartTooltip,
  ChartTooltipContent,
  type ChartConfig,
} from "@/components/ui/chart"

const chartData = [
  { week: "W1", signups: 412, activated: 238 },
  { week: "W2", signups: 468, activated: 301 },
  { week: "W3", signups: 395, activated: 254 },
  { week: "W4", signups: 530, activated: 362 },
  { week: "W5", signups: 588, activated: 417 },
  { week: "W6", signups: 561, activated: 431 },
  { week: "W7", signups: 642, activated: 489 },
]

const chartConfig = {
  signups: {
    label: "Sign-ups",
    color: "var(--chart-1)",
  },
  activated: {
    label: "Activated",
    color: "var(--chart-4)",
  },
} satisfies ChartConfig

export function ChartLine() {
  return (
    <ChartContainer
      aria-label="Line chart of sign-ups and activated accounts"
      config={chartConfig}
      className="h-60 w-full"
    >
      <LineChart data={chartData} margin={{ left: 4, right: 12, top: 8 }}>
        <CartesianGrid vertical={false} />
        <XAxis
          dataKey="week"
          tickLine={false}
          axisLine={false}
          tickMargin={8}
        />
        <YAxis tickLine={false} axisLine={false} tickMargin={8} width={36} />
        <ChartTooltip content={<ChartTooltipContent indicator="line" />} />
        <Line
          dataKey="signups"
          type="monotone"
          stroke="var(--color-signups)"
          strokeWidth={2}
          dot={false}
          activeDot={{ r: 4 }}
        />
        <Line
          dataKey="activated"
          type="monotone"
          stroke="var(--color-activated)"
          strokeWidth={2}
          dot={false}
          activeDot={{ r: 4 }}
        />
        <ChartLegend content={<ChartLegendContent />} />
      </LineChart>
    </ChartContainer>
  )
}

Barras apiladas

Las barras con el mismo stackId se apilan. Redondea solo los extremos exteriores, para que la pila se lea como una sola barra.

"use client"

import { Bar, BarChart, CartesianGrid, XAxis } from "recharts"

import {
  ChartContainer,
  ChartLegend,
  ChartLegendContent,
  ChartTooltip,
  ChartTooltipContent,
  type ChartConfig,
} from "@/components/ui/chart"

const chartData = [
  { quarter: "Q1", starter: 120, pro: 86, team: 34 },
  { quarter: "Q2", starter: 138, pro: 104, team: 51 },
  { quarter: "Q3", starter: 131, pro: 122, team: 69 },
  { quarter: "Q4", starter: 149, pro: 141, team: 88 },
]

const chartConfig = {
  starter: {
    label: "Starter",
    color: "var(--chart-1)",
  },
  pro: {
    label: "Pro",
    color: "var(--chart-2)",
  },
  team: {
    label: "Team",
    color: "var(--chart-3)",
  },
} satisfies ChartConfig

export function ChartStacked() {
  return (
    <ChartContainer
      aria-label="Stacked bar chart of Starter, Pro and Team plans"
      config={chartConfig}
      className="h-60 w-full max-w-md"
    >
      <BarChart data={chartData}>
        <CartesianGrid vertical={false} />
        <XAxis
          dataKey="quarter"
          tickLine={false}
          axisLine={false}
          tickMargin={10}
        />
        <ChartTooltip content={<ChartTooltipContent />} />
        <ChartLegend content={<ChartLegendContent />} />
        <Bar
          dataKey="starter"
          stackId="plans"
          fill="var(--color-starter)"
          radius={[0, 0, 4, 4]}
        />
        <Bar dataKey="pro" stackId="plans" fill="var(--color-pro)" />
        <Bar
          dataKey="team"
          stackId="plans"
          fill="var(--color-team)"
          radius={[4, 4, 0, 0]}
        />
      </BarChart>
    </ChartContainer>
  )
}

Barras horizontales

Define layout="vertical" en el gráfico e intercambia los tipos de eje. <LabelList /> imprime cada valor al final de su barra.

"use client"

import { Bar, BarChart, LabelList, XAxis, YAxis } from "recharts"

import {
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
  type ChartConfig,
} from "@/components/ui/chart"

const chartData = [
  { page: "Pricing", views: 4821 },
  { page: "Docs", views: 3902 },
  { page: "Changelog", views: 2214 },
  { page: "Blog", views: 1736 },
  { page: "Careers", views: 640 },
]

const chartConfig = {
  views: {
    label: "Views",
    color: "var(--chart-1)",
  },
} satisfies ChartConfig

export function ChartHorizontal() {
  return (
    <ChartContainer
      aria-label="Horizontal bar chart of page views"
      config={chartConfig}
      className="h-56 w-full max-w-md"
    >
      <BarChart data={chartData} layout="vertical" margin={{ right: 48 }}>
        <XAxis type="number" dataKey="views" hide />
        <YAxis
          type="category"
          dataKey="page"
          tickLine={false}
          axisLine={false}
          tickMargin={8}
          width={76}
        />
        <ChartTooltip
          cursor={false}
          content={<ChartTooltipContent hideLabel />}
        />
        <Bar dataKey="views" fill="var(--color-views)" radius={4} barSize={20}>
          <LabelList
            dataKey="views"
            position="right"
            offset={8}
            className="fill-foreground"
            formatter={(value) => Number(value).toLocaleString("en-US")}
          />
        </Bar>
      </BarChart>
    </ChartContainer>
  )
}

Donut

Cada sector toma su color de fill en los datos. nameKey en el tooltip y la leyenda busca en la config la etiqueta de cada sector.

"use client"

import { Label, Pie, PieChart } from "recharts"

import {
  ChartContainer,
  ChartLegend,
  ChartLegendContent,
  ChartTooltip,
  ChartTooltipContent,
  type ChartConfig,
} from "@/components/ui/chart"

const chartData = [
  { browser: "chrome", visitors: 275, fill: "var(--color-chrome)" },
  { browser: "safari", visitors: 200, fill: "var(--color-safari)" },
  { browser: "firefox", visitors: 187, fill: "var(--color-firefox)" },
  { browser: "edge", visitors: 173, fill: "var(--color-edge)" },
  { browser: "other", visitors: 90, fill: "var(--color-other)" },
]

const chartConfig = {
  visitors: {
    label: "Visitors",
  },
  chrome: {
    label: "Chrome",
    color: "var(--chart-1)",
  },
  safari: {
    label: "Safari",
    color: "var(--chart-2)",
  },
  firefox: {
    label: "Firefox",
    color: "var(--chart-3)",
  },
  edge: {
    label: "Edge",
    color: "var(--chart-4)",
  },
  other: {
    label: "Other",
    color: "var(--chart-5)",
  },
} satisfies ChartConfig

const total = chartData.reduce((sum, item) => sum + item.visitors, 0)

export function ChartPie() {
  return (
    <ChartContainer
      aria-label="Pie chart of visitors by browser"
      config={chartConfig}
      className="aspect-square h-72"
    >
      <PieChart>
        <ChartTooltip
          cursor={false}
          content={<ChartTooltipContent nameKey="browser" hideLabel />}
        />
        <Pie
          data={chartData}
          dataKey="visitors"
          nameKey="browser"
          innerRadius={58}
          paddingAngle={2}
          cornerRadius={4}
        >
          <Label
            content={({ viewBox }) => {
              if (!viewBox || !("cx" in viewBox)) {
                return null
              }
              return (
                <text
                  x={viewBox.cx}
                  y={viewBox.cy}
                  textAnchor="middle"
                  dominantBaseline="middle"
                >
                  <tspan
                    x={viewBox.cx}
                    y={viewBox.cy}
                    className="fill-foreground text-2xl font-semibold"
                  >
                    {total.toLocaleString("en-US")}
                  </tspan>
                  <tspan
                    x={viewBox.cx}
                    y={(viewBox.cy ?? 0) + 22}
                    className="fill-muted-foreground"
                  >
                    Visitors
                  </tspan>
                </text>
              )
            }}
          />
        </Pie>
        <ChartLegend content={<ChartLegendContent nameKey="browser" />} />
      </PieChart>
    </ChartContainer>
  )
}

Radar

Las cuadrículas y los ejes polares adoptan los mismos trazos y etiquetas atenuados que los cartesianos.

"use client"

import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from "recharts"

import {
  ChartContainer,
  ChartLegend,
  ChartLegendContent,
  ChartTooltip,
  ChartTooltipContent,
  type ChartConfig,
} from "@/components/ui/chart"

const chartData = [
  { skill: "Speed", current: 82, target: 90 },
  { skill: "Quality", current: 74, target: 85 },
  { skill: "Reach", current: 61, target: 70 },
  { skill: "Retention", current: 88, target: 85 },
  { skill: "Support", current: 69, target: 80 },
  { skill: "Pricing", current: 77, target: 75 },
]

const chartConfig = {
  current: {
    label: "Current",
    color: "var(--chart-1)",
  },
  target: {
    label: "Target",
    color: "var(--chart-3)",
  },
} satisfies ChartConfig

export function ChartRadar() {
  return (
    <ChartContainer
      aria-label="Radar chart of current and target scores"
      config={chartConfig}
      className="aspect-square h-80"
    >
      <RadarChart data={chartData}>
        <ChartTooltip content={<ChartTooltipContent indicator="line" />} />
        <PolarGrid />
        <PolarAngleAxis dataKey="skill" />
        <Radar
          dataKey="current"
          stroke="var(--color-current)"
          strokeWidth={2}
          fill="var(--color-current)"
          fillOpacity={0.15}
        />
        <Radar
          dataKey="target"
          stroke="var(--color-target)"
          strokeWidth={2}
          strokeDasharray="4 4"
          fill="none"
        />
        <ChartLegend content={<ChartLegendContent />} />
      </RadarChart>
    </ChartContainer>
  )
}

Tooltip

Cambia entre los indicadores dot, line y dashed, y oculta la etiqueta con hideLabel. defaultIndex en <ChartTooltip /> muestra un punto en el primer renderizado.

"use client"

import * as React from "react"
import { Bar, BarChart, XAxis } from "recharts"

import {
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
  type ChartTooltipContentProps,
  type ChartConfig,
} from "@/components/ui/chart"
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"

const chartData = [
  { day: "Mon", running: 450, swimming: 300 },
  { day: "Tue", running: 380, swimming: 420 },
  { day: "Wed", running: 520, swimming: 120 },
  { day: "Thu", running: 140, swimming: 550 },
  { day: "Fri", running: 600, swimming: 350 },
  { day: "Sat", running: 480, swimming: 400 },
]

const chartConfig = {
  running: {
    label: "Running",
    color: "var(--chart-1)",
  },
  swimming: {
    label: "Swimming",
    color: "var(--chart-2)",
  },
} satisfies ChartConfig

type Indicator = NonNullable<ChartTooltipContentProps["indicator"]>

const indicators: Indicator[] = ["dot", "line", "dashed"]

export function ChartTooltipIndicators() {
  const [indicator, setIndicator] = React.useState<Indicator>("dot")
  const [hideLabel, setHideLabel] = React.useState(false)

  return (
    <div className="flex w-full max-w-md flex-col items-center gap-4">
      <div className="flex flex-wrap justify-center gap-2">
        <ToggleGroup
          variant="outline"
          size="sm"
          aria-label="Indicator"
          value={[indicator]}
          onValueChange={(value) => {
            if (value.length > 0) {
              setIndicator(value[0] as Indicator)
            }
          }}
        >
          {indicators.map((item) => (
            <ToggleGroupItem key={item} value={item}>
              {item}
            </ToggleGroupItem>
          ))}
        </ToggleGroup>
        <ToggleGroup
          variant="outline"
          size="sm"
          aria-label="Label"
          value={hideLabel ? ["hidden"] : []}
          onValueChange={(value) => setHideLabel(value.length > 0)}
        >
          <ToggleGroupItem value="hidden">hideLabel</ToggleGroupItem>
        </ToggleGroup>
      </div>
      <ChartContainer
        aria-label="Bar chart of running and swimming time"
        config={chartConfig}
        className="h-52 w-full"
      >
        <BarChart data={chartData}>
          <XAxis
            dataKey="day"
            tickLine={false}
            axisLine={false}
            tickMargin={10}
          />
          <ChartTooltip
            defaultIndex={2}
            content={
              <ChartTooltipContent
                indicator={indicator}
                hideLabel={hideLabel}
              />
            }
          />
          <Bar
            dataKey="running"
            stackId="a"
            fill="var(--color-running)"
            radius={[0, 0, 4, 4]}
          />
          <Bar
            dataKey="swimming"
            stackId="a"
            fill="var(--color-swimming)"
            radius={[4, 4, 0, 0]}
          />
        </BarChart>
      </ChartContainer>
    </div>
  )
}

Dar formato a los valores

valueFormatter da formato al número y conserva el indicador y el nombre. labelFormatter hace lo mismo con la etiqueta. Para reemplazar una fila completa, usa formatter.

"use client"

import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from "recharts"

import {
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
  type ChartConfig,
} from "@/components/ui/chart"

const chartData = [
  { month: "2026-01", revenue: 18420.5 },
  { month: "2026-02", revenue: 21310 },
  { month: "2026-03", revenue: 19875.25 },
  { month: "2026-04", revenue: 24960 },
  { month: "2026-05", revenue: 28140.75 },
  { month: "2026-06", revenue: 31295 },
]

const chartConfig = {
  revenue: {
    label: "Revenue",
    color: "var(--chart-1)",
  },
} satisfies ChartConfig

const currency = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
})

const compactCurrency = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  notation: "compact",
})

const monthFormat = new Intl.DateTimeFormat("en-US", {
  month: "long",
  year: "numeric",
  timeZone: "UTC",
})

function formatMonth(value: unknown) {
  return monthFormat.format(new Date(`${value}-01T00:00:00Z`))
}

export function ChartValueFormat() {
  return (
    <ChartContainer
      aria-label="Area chart of revenue"
      config={chartConfig}
      className="h-56 w-full max-w-md"
    >
      <AreaChart data={chartData} margin={{ left: 4, right: 12, top: 8 }}>
        <CartesianGrid vertical={false} />
        <XAxis
          dataKey="month"
          tickLine={false}
          axisLine={false}
          tickMargin={8}
          tickFormatter={(value) => formatMonth(value).slice(0, 3)}
        />
        <YAxis
          tickLine={false}
          axisLine={false}
          tickMargin={8}
          width={48}
          tickFormatter={(value) => compactCurrency.format(value)}
        />
        <ChartTooltip
          content={
            <ChartTooltipContent
              indicator="line"
              labelFormatter={formatMonth}
              valueFormatter={(value) => currency.format(Number(value))}
            />
          }
        />
        <Area
          dataKey="revenue"
          type="monotone"
          stroke="var(--color-revenue)"
          strokeWidth={2}
          fill="var(--color-revenue)"
          fillOpacity={0.1}
        />
      </AreaChart>
    </ChartContainer>
  )
}

Iconos

Un icon en la config reemplaza la clave de color en el tooltip y la leyenda.

"use client"

import {
  IconDeviceDesktop,
  IconDeviceMobile,
  IconDeviceTablet,
} from "@tabler/icons-react"
import { Bar, BarChart, CartesianGrid, XAxis } from "recharts"

import {
  ChartContainer,
  ChartLegend,
  ChartLegendContent,
  ChartTooltip,
  ChartTooltipContent,
  type ChartConfig,
} from "@/components/ui/chart"

const chartData = [
  { month: "Jan", desktop: 186, tablet: 42, mobile: 80 },
  { month: "Feb", desktop: 305, tablet: 61, mobile: 200 },
  { month: "Mar", desktop: 237, tablet: 54, mobile: 120 },
  { month: "Apr", desktop: 173, tablet: 70, mobile: 190 },
]

const chartConfig = {
  desktop: {
    label: "Desktop",
    icon: IconDeviceDesktop,
    color: "var(--chart-1)",
  },
  tablet: {
    label: "Tablet",
    icon: IconDeviceTablet,
    color: "var(--chart-3)",
  },
  mobile: {
    label: "Mobile",
    icon: IconDeviceMobile,
    color: "var(--chart-2)",
  },
} satisfies ChartConfig

export function ChartIcons() {
  return (
    <ChartContainer
      aria-label="Bar chart of desktop, tablet and mobile visitors"
      config={chartConfig}
      className="h-56 w-full max-w-md"
    >
      <BarChart data={chartData}>
        <CartesianGrid vertical={false} />
        <XAxis
          dataKey="month"
          tickLine={false}
          axisLine={false}
          tickMargin={10}
        />
        <ChartTooltip content={<ChartTooltipContent />} />
        <ChartLegend content={<ChartLegendContent />} />
        <Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
        <Bar dataKey="tablet" fill="var(--color-tablet)" radius={4} />
        <Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
      </BarChart>
    </ChartContainer>
  )
}

Colores claro y oscuro

Un objeto theme elige un color distinto en cada tema. Cambia el tema del sitio para verlo cambiar.

"use client"

import { CartesianGrid, Line, LineChart, XAxis } from "recharts"

import {
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
  type ChartConfig,
} from "@/components/ui/chart"

const chartData = [
  { hour: "08:00", latency: 182 },
  { hour: "10:00", latency: 164 },
  { hour: "12:00", latency: 231 },
  { hour: "14:00", latency: 205 },
  { hour: "16:00", latency: 148 },
  { hour: "18:00", latency: 171 },
]

const chartConfig = {
  latency: {
    label: "Latency (ms)",
    theme: {
      light: "oklch(0.5 0.17 285)",
      dark: "oklch(0.75 0.14 190)",
    },
  },
} satisfies ChartConfig

export function ChartTheme() {
  return (
    <ChartContainer
      aria-label="Line chart of latency in milliseconds"
      config={chartConfig}
      className="h-52 w-full max-w-md"
    >
      <LineChart data={chartData} margin={{ left: 12, right: 12, top: 8 }}>
        <CartesianGrid vertical={false} />
        <XAxis
          dataKey="hour"
          padding={{ left: 16, right: 16 }}
          tickLine={false}
          axisLine={false}
          tickMargin={8}
        />
        <ChartTooltip content={<ChartTooltipContent indicator="line" />} />
        <Line
          dataKey="latency"
          type="linear"
          stroke="var(--color-latency)"
          strokeWidth={2}
          dot={{ r: 3, fill: "var(--color-latency)" }}
        />
      </LineChart>
    </ChartContainer>
  )
}

Valores negativos

Colorea cada barra con <Cell /> y marca el cero con <ReferenceLine />.

"use client"

import {
  Bar,
  BarChart,
  CartesianGrid,
  Cell,
  ReferenceLine,
  XAxis,
} from "recharts"

import {
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
  type ChartConfig,
} from "@/components/ui/chart"

const chartData = [
  { month: "Jan", change: 12.4 },
  { month: "Feb", change: -4.1 },
  { month: "Mar", change: 8.7 },
  { month: "Apr", change: -9.3 },
  { month: "May", change: 3.2 },
  { month: "Jun", change: 15.8 },
]

const chartConfig = {
  change: {
    label: "Change",
  },
  gain: {
    label: "Gain",
    color: "var(--chart-1)",
  },
  loss: {
    label: "Loss",
    color: "var(--chart-5)",
  },
} satisfies ChartConfig

export function ChartNegative() {
  return (
    <ChartContainer
      aria-label="Bar chart of gains and losses"
      config={chartConfig}
      className="h-56 w-full max-w-md"
    >
      <BarChart data={chartData}>
        <CartesianGrid vertical={false} />
        <XAxis
          dataKey="month"
          tickLine={false}
          axisLine={false}
          tickMargin={10}
        />
        <ReferenceLine y={0} />
        <ChartTooltip
          cursor={false}
          content={
            <ChartTooltipContent
              hideIndicator
              valueFormatter={(value) =>
                `${Number(value) > 0 ? "+" : ""}${value}%`
              }
            />
          }
        />
        <Bar dataKey="change" radius={4}>
          {chartData.map((item) => (
            <Cell
              key={item.month}
              fill={item.change < 0 ? "var(--color-loss)" : "var(--color-gain)"}
            />
          ))}
        </Bar>
      </BarChart>
    </ChartContainer>
  )
}

Etiquetas largas

Los nombres de serie largos se ajustan en la leyenda y el tooltip, y los valores grandes permanecen en una sola línea a su lado.

"use client"

import { Bar, BarChart, XAxis } from "recharts"

import {
  ChartContainer,
  ChartLegend,
  ChartLegendContent,
  ChartTooltip,
  ChartTooltipContent,
  type ChartConfig,
} from "@/components/ui/chart"

const chartData = [
  {
    region: "North America and the Caribbean",
    enterprise: 1284032,
    midMarket: 842311,
    selfServe: 402118,
    partners: 220940,
    marketplace: 98110,
  },
  {
    region: "Europe, Middle East and Africa",
    enterprise: 1032544,
    midMarket: 760201,
    selfServe: 515720,
    partners: 180332,
    marketplace: 121004,
  },
  {
    region: "Asia Pacific",
    enterprise: 690210,
    midMarket: 612090,
    selfServe: 688402,
    partners: 140220,
    marketplace: 160550,
  },
]

const chartConfig = {
  enterprise: {
    label: "Enterprise contracts (annual)",
    color: "var(--chart-1)",
  },
  midMarket: {
    label: "Mid-market subscriptions",
    color: "var(--chart-2)",
  },
  selfServe: {
    label: "Self-serve card payments",
    color: "var(--chart-3)",
  },
  partners: {
    label: "Reseller and agency partners",
    color: "var(--chart-4)",
  },
  marketplace: {
    label: "Cloud marketplace listings",
    color: "var(--chart-5)",
  },
} satisfies ChartConfig

export function ChartLongLabels() {
  return (
    <ChartContainer
      aria-label="Bar chart of revenue by sales channel"
      config={chartConfig}
      className="h-80 w-full max-w-sm"
    >
      <BarChart data={chartData}>
        <XAxis
          dataKey="region"
          tickLine={false}
          axisLine={false}
          tickMargin={10}
          tickFormatter={(value) => value.split(/[ ,]/)[0]}
        />
        <ChartTooltip content={<ChartTooltipContent />} />
        <ChartLegend content={<ChartLegendContent />} />
        <Bar dataKey="enterprise" stackId="a" fill="var(--color-enterprise)" />
        <Bar dataKey="midMarket" stackId="a" fill="var(--color-midMarket)" />
        <Bar dataKey="selfServe" stackId="a" fill="var(--color-selfServe)" />
        <Bar dataKey="partners" stackId="a" fill="var(--color-partners)" />
        <Bar
          dataKey="marketplace"
          stackId="a"
          fill="var(--color-marketplace)"
          radius={[4, 4, 0, 0]}
        />
      </BarChart>
    </ChartContainer>
  )
}

De derecha a izquierda

Recharts no refleja los ejes por sí solo. Define reversed en el eje x y mueve el eje y a la derecha. Pasa locale al tooltip para mostrar los dígitos del lector.

"use client"

import { Bar, BarChart, CartesianGrid, XAxis, YAxis } from "recharts"

import {
  ChartContainer,
  ChartLegend,
  ChartLegendContent,
  ChartTooltip,
  ChartTooltipContent,
  type ChartConfig,
} from "@/components/ui/chart"

const chartData = [
  { month: "يناير", desktop: 186, mobile: 80 },
  { month: "فبراير", desktop: 305, mobile: 200 },
  { month: "مارس", desktop: 237, mobile: 120 },
  { month: "أبريل", desktop: 73, mobile: 190 },
  { month: "مايو", desktop: 209, mobile: 130 },
  { month: "يونيو", desktop: 214, mobile: 140 },
]

const chartConfig = {
  desktop: {
    label: "سطح المكتب",
    color: "var(--chart-1)",
  },
  mobile: {
    label: "الجوال",
    color: "var(--chart-2)",
  },
} satisfies ChartConfig

const numbers = new Intl.NumberFormat("ar-EG")

export function ChartRtl() {
  return (
    <div dir="rtl" className="w-full max-w-md">
      <ChartContainer
        aria-label="مخطط أعمدة لزوار سطح المكتب والجوال"
        config={chartConfig}
        className="h-60 w-full"
      >
        <BarChart data={chartData}>
          <CartesianGrid vertical={false} />
          <XAxis
            dataKey="month"
            reversed
            tickLine={false}
            axisLine={false}
            tickMargin={10}
          />
          <YAxis
            orientation="right"
            tickLine={false}
            axisLine={false}
            tickMargin={8}
            width={36}
            tickFormatter={(value) => numbers.format(value)}
          />
          <ChartTooltip content={<ChartTooltipContent locale="ar-EG" />} />
          <ChartLegend content={<ChartLegendContent />} />
          <Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
          <Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
        </BarChart>
      </ChartContainer>
    </div>
  )
}

Recharts activa accessibilityLayer por defecto, así que el gráfico es una sola parada del tabulador por la que te mueves punto por punto.

KeyAcción
TabDa foco al gráfico y muestra un anillo de foco.
←→Mueve el tooltip al punto siguiente o anterior. En un eje invertido las teclas siguen la pantalla.
EnterMuestra u oculta el tooltip en el punto actual.
  • Para los lectores de pantalla, los gráficos son imágenes. Nombra cada uno con un título visible cercano o un aria-label en el gráfico de Recharts, y ofrece una tabla cuando se necesiten los valores exactos.
  • El tooltip y la leyenda nombran cada serie en texto, así que el lector nunca tiene que depender solo de los colores.
  • Con movimiento reducido, Recharts omite sus animaciones de entrada y el tooltip salta entre puntos en lugar de deslizarse.
  • Los valores del tooltip se formatean en en-US salvo que pases locale, para que el servidor y el navegador rendericen el mismo texto.

Las partes se apoyan en Recharts. Todas las props de Recharts siguen funcionando en los componentes de gráfico que pongas dentro.

Proporciona la config, escribe las variables de color y renderiza un <ResponsiveContainer /> de Recharts alrededor de su hijo. Acepta todas las props de <div>.

PropTipoPredeterminado
configEtiquetas, iconos y colores para cada clave de datos.
ChartConfig–
childrenUn gráfico de Recharts, como <BarChart />.
ReactElement–
initialDimensionEl tamaño usado antes de medir el contenedor.
{ width: number; height: number }{ width: 320, height: 200 }
idNombra el gráfico en data-chart. Se genera si se omite.
string–
AtributoDescripción
data-slot="chart"El contenedor.
data-chartEl id al que se limitan las variables de color.
--color-KEYUna variable de color por cada clave configurada.
PropTipoPredeterminado
label
ReactNode–
iconReemplaza la clave de color en el tooltip y la leyenda.
ComponentType–
colorCualquier color o variable CSS.
string–
themeÚsalo en lugar de color para tener un color por tema.
{ light: string; dark: string }–

El <Tooltip /> de Recharts, con un deslizamiento más corto entre puntos. Acepta todas las props de tooltip de Recharts.

PropTipoPredeterminado
contentNormalmente <ChartTooltipContent />.
ReactElement | (props) => ReactNode–
animationDuration
number200
animationEasing
string"ease-out"
defaultIndexMuestra el tooltip en este punto en el primer renderizado.
number–
PropTipoPredeterminado
indicator
"dot" | "line" | "dashed""dot"
hideLabel
booleanfalse
hideIndicator
booleanfalse
labelKeyLa clave de la config o de los datos que se usa para la etiqueta.
string–
nameKeyLa clave de la config o de los datos que se usa para cada nombre.
string–
valueFormatterDa formato a cada valor y conserva el indicador y el nombre.
(value, name, item) => ReactNode–
labelFormatter
(label, payload) => ReactNode–
formatterReemplaza cada fila.
(value, name, item, index, payload) => ReactNode–
localeDa formato a los valores numéricos.
Intl.LocalesArgument"en-US"
colorUn color de indicador para todas las filas.
string–
className
string–
labelClassName
string–
AtributoDescripción
data-slot="chart-tooltip"La caja.
data-slot="chart-tooltip-label"La etiqueta.
data-slot="chart-tooltip-item"Una fila por serie.
data-slot="chart-tooltip-indicator"La clave de color.
data-indicatorEn la clave: dot, line o dashed.
--chart-indicatorEl color de la clave.

El <Legend /> de Recharts. Acepta todas las props de leyenda de Recharts y lista las series en el orden en que las declaras en lugar de alfabéticamente.

PropTipoPredeterminado
contentNormalmente <ChartLegendContent />.
ReactElement | (props) => ReactNode–
itemSorternull conserva el orden declarado.
"value" | "dataKey" | (item) => number | string | nullnull
PropTipoPredeterminado
hideIcon
booleanfalse
nameKeyLa clave de la config o de los datos que se usa para cada nombre.
string–
className
string–
AtributoDescripción
data-slot="chart-legend"La lista.
data-slot="chart-legend-item"Una entrada por serie.
data-slot="chart-legend-indicator"La muestra de color.

Devuelve { config } dentro de un <ChartContainer />, para construir tu propio contenido de tooltip o leyenda.

Usado en bloques

Bloques que se construyen sobre Chart.