# React Bar Chart

A React bar chart with Chart.js: compare monthly values in rounded bars that take their colors from the theme and follow light and dark mode.

A bar chart compares values between categories, such as sales per month. The length of each bar shows at a glance which category is ahead. In [AdminKit for React](/react/) you draw it with the `ChartJs` component, a wrapper around Chart.js. It is in the free and PRO versions. AdminKit PRO also has `ApexChart`, which draws the chart with ApexCharts.

Both components take a function of the theme colors instead of a fixed configuration, so the chart follows light and dark mode. [Chart setup](/react/docs/charts/overview/) explains how that works.

## Example

This example sets last year against this year, month by month. You don't round the bars yourself: AdminKit's Chart.js defaults give them rounded top corners (`borderRadius: 10`).

```html
<div class="chart">
  <canvas id="chartjs-bar"></canvas>
</div>

<script>
adminkit.chartjs("#chartjs-bar", function (theme) {
  return {
    type: "bar",
    data: {
      labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
      datasets: [{
        label: "Last year",
        backgroundColor: theme.primary,
        borderColor: theme.primary,
        hoverBackgroundColor: theme.primary,
        hoverBorderColor: theme.primary,
        data: [54, 67, 41, 55, 62, 45, 55, 73, 60, 76, 48, 79],
        barPercentage: .75,
        categoryPercentage: .5
      }, {
        label: "This year",
        backgroundColor: "#dee2e6",
        borderColor: "#dee2e6",
        hoverBackgroundColor: "#dee2e6",
        hoverBorderColor: "#dee2e6",
        data: [69, 66, 24, 48, 52, 51, 44, 53, 62, 79, 51, 68],
        barPercentage: .75,
        categoryPercentage: .5
      }]
    },
    options: {
      maintainAspectRatio: false,
      plugins: {
        legend: {
          display: false
        }
      },
      scales: {
        y: {
          grid: {
            display: false
          },
          border: {
            display: false
          },
          stacked: false,
          ticks: {
            stepSize: 20
          }
        },
        x: {
          stacked: false,
          grid: {
            color: "transparent"
          },
          border: {
            display: false
          }
        }
      }
    }
  };
});
</script>
```
```tsx code
import { ChartJs } from "@/components/plugins/chartjs";

export function SalesBarChart() {
  return (
    <div className="chart">
      <ChartJs
        aria-label="Sales per month, last year and this year"
        config={(theme) => ({
          type: "bar",
          data: {
            labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
            datasets: [
              {
                label: "Last year",
                backgroundColor: theme.primary,
                borderColor: theme.primary,
                hoverBackgroundColor: theme.primary,
                hoverBorderColor: theme.primary,
                data: [54, 67, 41, 55, 62, 45, 55, 73, 60, 76, 48, 79],
                barPercentage: 0.75,
                categoryPercentage: 0.5,
              },
              {
                label: "This year",
                backgroundColor: "#dee2e6",
                borderColor: "#dee2e6",
                hoverBackgroundColor: "#dee2e6",
                hoverBorderColor: "#dee2e6",
                data: [69, 66, 24, 48, 52, 51, 44, 53, 62, 79, 51, 68],
                barPercentage: 0.75,
                categoryPercentage: 0.5,
              },
            ],
          },
          options: {
            maintainAspectRatio: false,
            plugins: { legend: { display: false } },
            scales: {
              y: {
                grid: { display: false },
                border: { display: false },
                stacked: false,
                ticks: { stepSize: 20 },
              },
              x: {
                stacked: false,
                grid: { color: "transparent" },
                border: { display: false },
              },
            },
          },
        })}
      />
    </div>
  );
}
```

Render the component from a page in `src/routes/`. Each page loads when it is opened (`React.lazy` in `src/app.tsx`), so Chart.js is only downloaded with the first page that draws a chart. A new page also needs an entry in `src/data/pages.json` (see [Add a page](/react/docs/getting-started/project-structure/#add-a-page)).

```tsx title="src/routes/reports.tsx"
import { SalesBarChart } from "@/components/sales-bar-chart";

export default function Page() {
  return (
    <div className="card">
      <div className="card-header">
        <h2 className="card-title">Sales</h2>
      </div>
      <div className="card-body">
        <SalesBarChart />
      </div>
    </div>
  );
}
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `config` | `(theme: Theme) => ChartConfiguration` | | The Chart.js configuration: `type`, `data` and `options`. Called again with the new colors when the color mode changes |

Other props, such as `id` and `aria-label`, go to the `<canvas>`. [Chart setup](/react/docs/charts/overview/#chartjs) lists the container heights and the defaults AdminKit sets.

## Colors in dark mode

A fixed color does not follow the mode. The "This year" bars keep the `#dee2e6` of the HTML example, so they stay light gray in dark mode too. `theme["gray-300"]` is the same gray in light mode and follows the gray scale of dark mode:

```tsx
backgroundColor: theme["gray-300"],
```

## Horizontal and stacked bars

For bars that run sideways or add up, set two Chart.js options. `indexAxis: "y"` draws the bars horizontally, and `stacked: true` on both scales stacks the series:

```tsx
options: {
  indexAxis: "y",
  scales: {
    x: { stacked: true },
    y: { stacked: true },
  },
},
```

## ApexCharts example

> This example is only available in **AdminKit PRO**. [Learn more](/pricing/#react).

With `ApexChart`, this example draws a horizontal stacked bar chart. `plotOptions.bar.horizontal` turns the bars sideways, and `chart.stacked` adds up the series. The container has the chart's height, so the skeleton fills the same space while ApexCharts loads.

```html
<div id="apexcharts-bar"></div>

<script>
var options = {
  chart: {
    height: 350,
    type: "bar",
    stacked: true,
  },
  plotOptions: {
    bar: {
      horizontal: true,
    },
  },
  stroke: {
    width: 1,
    colors: ["#fff"]
  },
  series: [{
    name: "Marine Sprite",
    data: [44, 55, 41, 37, 22, 43, 21]
  }, {
    name: "Striking Calf",
    data: [53, 32, 33, 52, 13, 43, 32]
  }, {
    name: "Tank Picture",
    data: [12, 17, 11, 9, 15, 11, 20]
  }, {
    name: "Bucket Slope",
    data: [9, 7, 5, 8, 6, 9, 4]
  }, {
    name: "Reborn Kid",
    data: [25, 12, 19, 32, 25, 24, 10]
  }],
  xaxis: {
    categories: [2020, 2021, 2022, 2023, 2024, 2025, 2026],
    labels: {
      formatter: function(val) {
        return val + "K"
      }
    }
  },
  yaxis: {
    title: {
      text: undefined
    },
  },
  tooltip: {
    y: {
      formatter: function(val) {
        return val + "K"
      }
    }
  },
  fill: {
    opacity: 1
  },
  legend: {
    position: "top",
    horizontalAlign: "left",
    offsetX: 40
  }
}
adminkit.apexcharts("#apexcharts-bar", function () {
  return options;
});
</script>
```
```tsx code
import { ApexChart } from "@/components/plugins/apexcharts";

export function ProductsBarChart() {
  return (
    <div className="position-relative" style={{ minHeight: 365 }}>
      <ApexChart
        options={() => ({
          chart: { height: 350, type: "bar", stacked: true },
          plotOptions: { bar: { horizontal: true } },
          stroke: { width: 1, colors: ["#fff"] },
          series: [
            { name: "Marine Sprite", data: [44, 55, 41, 37, 22, 43, 21] },
            { name: "Striking Calf", data: [53, 32, 33, 52, 13, 43, 32] },
            { name: "Tank Picture", data: [12, 17, 11, 9, 15, 11, 20] },
            { name: "Bucket Slope", data: [9, 7, 5, 8, 6, 9, 4] },
            { name: "Reborn Kid", data: [25, 12, 19, 32, 25, 24, 10] },
          ],
          xaxis: {
            categories: [2020, 2021, 2022, 2023, 2024, 2025, 2026],
            labels: { formatter: (val: string) => val + "K" },
          },
          yaxis: { title: { text: undefined } },
          tooltip: { y: { formatter: (val: number) => val + "K" } },
          fill: { opacity: 1 },
          legend: { position: "top", horizontalAlign: "left", offsetX: 40 },
        })}
      />
    </div>
  );
}
```

The options set no colors, so the series take the primary, success, warning, danger and info colors of the current mode. The 1px `#fff` stroke between the stacked parts stays white in dark mode. Use `theme.white`, the surface color, for a stroke that follows the mode.

## Accessibility

- `ChartJs` renders the `<canvas>` with `role="img"`. Screen readers do not read what is drawn on it. Give it an `aria-label` that says what the chart shows, and put the figures that matter in text too.
- The Chart.js example hides the legend, so the two series differ only by color. Name them in the card title or text, or turn the legend on.
- Under `prefers-reduced-motion`, both components draw the chart without the entrance animation.

## Related

- [Next.js bar chart](/nextjs/docs/charts/bar-chart/): the same chart in AdminKit for Next.js
- [Bootstrap 5 bar chart](/bootstrap/docs/charts/bar-chart/): the bar chart of the HTML version
- [Chart setup](/react/docs/charts/overview/): the `ChartJs`, `ApexChart` and `VectorMap` components
- [Line chart](/react/docs/charts/line-chart/): values over time
- [Chart.js demo](https://react-demo.adminkit.io/charts-chartjs) and [ApexCharts demo](https://react-demo.adminkit.io/charts-apexcharts)

---

Canonical HTML page: https://adminkit.io/react/docs/charts/bar-chart/

Site overview for agents: https://adminkit.io/llms.txt (expanded: https://adminkit.io/llms-full.txt) · Documentation: https://adminkit.io/bootstrap/docs/ · Questions: support@adminkit.io
