Visualization

Bar Chart

Graph with bars to compare values across categories.

Installation

  1. 1

    Install dependencies:

    npm i recharts
  2. 2

    Add useOnWindowResize.ts hook:

    Copy and paste the code into your project’s hooks or component directory.
    // Tremor useOnWindowResize [v0.0.0]
    import * as React from "react"
    export const useOnWindowResize = (handler: { (): void }) => {  React.useEffect(() => {    const handleResize = () => {      handler()    }    handleResize()    window.addEventListener("resize", handleResize)
        return () => window.removeEventListener("resize", handleResize)  }, [handler])}
    
  3. 3

    Add component:

    Copy and paste the code into your project’s component directory. Do not forget to update the import paths. If you have not added the required chartUtils.ts, check out the add utilities and helpers section in installation.
    // Tremor BarChart [v0.2.1]/* eslint-disable @typescript-eslint/no-explicit-any */
    "use client"
    import React from "react"import { RiArrowLeftSLine, RiArrowRightSLine } from "@remixicon/react"import {  Bar,  CartesianGrid,  Label,  BarChart as RechartsBarChart,  Legend as RechartsLegend,  ResponsiveContainer,  Tooltip,  XAxis,  YAxis,} from "recharts"import { AxisDomain } from "recharts/types/util/types"
    import {  AvailableChartColors,  AvailableChartColorsKeys,  constructCategoryColors,  getColorClassName,  getYAxisDomain,} from "@/lib/chartUtils"import { useOnWindowResize } from "@/lib/useOnWindowResize"import { cx } from "@/lib/utils"
    //#region Shape
    function deepEqual<T>(obj1: T, obj2: T): boolean {  if (obj1 === obj2) return true
      if (    typeof obj1 !== "object" ||    typeof obj2 !== "object" ||    obj1 === null ||    obj2 === null  ) {    return false  }
      const keys1 = Object.keys(obj1) as Array<keyof T>  const keys2 = Object.keys(obj2) as Array<keyof T>
      if (keys1.length !== keys2.length) return false
      for (const key of keys1) {    if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) return false  }
      return true}
    const renderShape = (  props: any,  activeBar: any | undefined,  activeLegend: string | undefined,  layout: string,) => {  const { fillOpacity, name, payload, value } = props  let { x, width, y, height } = props
      if (layout === "horizontal" && height < 0) {    y += height    height = Math.abs(height) // height must be a positive number  } else if (layout === "vertical" && width < 0) {    x += width    width = Math.abs(width) // width must be a positive number  }
      return (    <rect      x={x}      y={y}      width={width}      height={height}      opacity={        activeBar || (activeLegend && activeLegend !== name)          ? deepEqual(activeBar, { ...payload, value })            ? fillOpacity            : 0.3          : fillOpacity      }    />  )}
    //#region Legend
    interface LegendItemProps {  name: string  color: AvailableChartColorsKeys  onClick?: (name: string, color: AvailableChartColorsKeys) => void  activeLegend?: string}
    const LegendItem = ({  name,  color,  onClick,  activeLegend,}: LegendItemProps) => {  const hasOnValueChange = !!onClick  return (    <li      className={cx(        // base        "group inline-flex flex-nowrap items-center gap-1.5 whitespace-nowrap rounded px-2 py-1 transition",        hasOnValueChange          ? "cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800"          : "cursor-default",      )}      onClick={(e) => {        e.stopPropagation()        onClick?.(name, color)      }}    >      <span        className={cx(          "size-2 shrink-0 rounded-sm",          getColorClassName(color, "bg"),          activeLegend && activeLegend !== name ? "opacity-40" : "opacity-100",        )}        aria-hidden={true}      />      <p        className={cx(          // base          "truncate whitespace-nowrap text-xs",          // text color          "text-gray-700 dark:text-gray-300",          hasOnValueChange &&            "group-hover:text-gray-900 dark:group-hover:text-gray-50",          activeLegend && activeLegend !== name ? "opacity-40" : "opacity-100",        )}      >        {name}      </p>    </li>  )}
    interface ScrollButtonProps {  icon: React.ElementType  onClick?: () => void  disabled?: boolean}
    const ScrollButton = ({ icon, onClick, disabled }: ScrollButtonProps) => {  const Icon = icon  const [isPressed, setIsPressed] = React.useState(false)  const intervalRef = React.useRef<NodeJS.Timeout | null>(null)
      React.useEffect(() => {    if (isPressed) {      intervalRef.current = setInterval(() => {        onClick?.()      }, 300)    } else {      clearInterval(intervalRef.current as NodeJS.Timeout)    }    return () => clearInterval(intervalRef.current as NodeJS.Timeout)  }, [isPressed, onClick])
      React.useEffect(() => {    if (disabled) {      clearInterval(intervalRef.current as NodeJS.Timeout)      setIsPressed(false)    }  }, [disabled])
      return (    <button      type="button"      className={cx(        // base        "group inline-flex size-5 items-center truncate rounded transition",        disabled          ? "cursor-not-allowed text-gray-400 dark:text-gray-600"          : "cursor-pointer text-gray-700 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-gray-50",      )}      disabled={disabled}      onClick={(e) => {        e.stopPropagation()        onClick?.()      }}      onMouseDown={(e) => {        e.stopPropagation()        setIsPressed(true)      }}      onMouseUp={(e) => {        e.stopPropagation()        setIsPressed(false)      }}    >      <Icon className="size-full" aria-hidden="true" />    </button>  )}
    interface LegendProps extends React.OlHTMLAttributes<HTMLOListElement> {  categories: string[]  colors?: AvailableChartColorsKeys[]  onClickLegendItem?: (category: string, color: string) => void  activeLegend?: string  enableLegendSlider?: boolean}
    type HasScrollProps = {  left: boolean  right: boolean}
    const Legend = React.forwardRef<HTMLOListElement, LegendProps>((props, ref) => {  const {    categories,    colors = AvailableChartColors,    className,    onClickLegendItem,    activeLegend,    enableLegendSlider = false,    ...other  } = props  const scrollableRef = React.useRef<HTMLInputElement>(null)  const scrollButtonsRef = React.useRef<HTMLDivElement>(null)  const [hasScroll, setHasScroll] = React.useState<HasScrollProps | null>(null)  const [isKeyDowned, setIsKeyDowned] = React.useState<string | null>(null)  const intervalRef = React.useRef<NodeJS.Timeout | null>(null)
      const checkScroll = React.useCallback(() => {    const scrollable = scrollableRef?.current    if (!scrollable) return
        const hasLeftScroll = scrollable.scrollLeft > 0    const hasRightScroll =      scrollable.scrollWidth - scrollable.clientWidth > scrollable.scrollLeft
        setHasScroll({ left: hasLeftScroll, right: hasRightScroll })  }, [setHasScroll])
      const scrollToTest = React.useCallback(    (direction: "left" | "right") => {      const element = scrollableRef?.current      const scrollButtons = scrollButtonsRef?.current      const scrollButtonsWith = scrollButtons?.clientWidth ?? 0      const width = element?.clientWidth ?? 0
          if (element && enableLegendSlider) {        element.scrollTo({          left:            direction === "left"              ? element.scrollLeft - width + scrollButtonsWith              : element.scrollLeft + width - scrollButtonsWith,          behavior: "smooth",        })        setTimeout(() => {          checkScroll()        }, 400)      }    },    [enableLegendSlider, checkScroll],  )
      React.useEffect(() => {    const keyDownHandler = (key: string) => {      if (key === "ArrowLeft") {        scrollToTest("left")      } else if (key === "ArrowRight") {        scrollToTest("right")      }    }    if (isKeyDowned) {      keyDownHandler(isKeyDowned)      intervalRef.current = setInterval(() => {        keyDownHandler(isKeyDowned)      }, 300)    } else {      clearInterval(intervalRef.current as NodeJS.Timeout)    }    return () => clearInterval(intervalRef.current as NodeJS.Timeout)  }, [isKeyDowned, scrollToTest])
      const keyDown = (e: KeyboardEvent) => {    e.stopPropagation()    if (e.key === "ArrowLeft" || e.key === "ArrowRight") {      e.preventDefault()      setIsKeyDowned(e.key)    }  }  const keyUp = (e: KeyboardEvent) => {    e.stopPropagation()    setIsKeyDowned(null)  }
      React.useEffect(() => {    const scrollable = scrollableRef?.current    if (enableLegendSlider) {      checkScroll()      scrollable?.addEventListener("keydown", keyDown)      scrollable?.addEventListener("keyup", keyUp)    }
        return () => {      scrollable?.removeEventListener("keydown", keyDown)      scrollable?.removeEventListener("keyup", keyUp)    }  }, [checkScroll, enableLegendSlider])
      return (    <ol      ref={ref}      className={cx("relative overflow-hidden", className)}      {...other}    >      <div        ref={scrollableRef}        tabIndex={0}        className={cx(          "flex h-full",          enableLegendSlider            ? hasScroll?.right || hasScroll?.left              ? "snap-mandatory items-center overflow-auto pl-4 pr-12 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"              : ""            : "flex-wrap",        )}      >        {categories.map((category, index) => (          <LegendItem            key={`item-${index}`}            name={category}            color={colors[index] as AvailableChartColorsKeys}            onClick={onClickLegendItem}            activeLegend={activeLegend}          />        ))}      </div>      {enableLegendSlider && (hasScroll?.right || hasScroll?.left) ? (        <>          <div            className={cx(              // base              "absolute bottom-0 right-0 top-0 flex h-full items-center justify-center pr-1",              // background color              "bg-white dark:bg-gray-950",            )}          >            <ScrollButton              icon={RiArrowLeftSLine}              onClick={() => {                setIsKeyDowned(null)                scrollToTest("left")              }}              disabled={!hasScroll?.left}            />            <ScrollButton              icon={RiArrowRightSLine}              onClick={() => {                setIsKeyDowned(null)                scrollToTest("right")              }}              disabled={!hasScroll?.right}            />          </div>        </>      ) : null}    </ol>  )})
    Legend.displayName = "Legend"
    const ChartLegend = (  { payload }: any,  categoryColors: Map<string, AvailableChartColorsKeys>,  setLegendHeight: React.Dispatch<React.SetStateAction<number>>,  activeLegend: string | undefined,  onClick?: (category: string, color: string) => void,  enableLegendSlider?: boolean,  legendPosition?: "left" | "center" | "right",  yAxisWidth?: number,) => {  const legendRef = React.useRef<HTMLDivElement>(null)
      useOnWindowResize(() => {    const calculateHeight = (height: number | undefined) =>      height ? Number(height) + 15 : 60    setLegendHeight(calculateHeight(legendRef.current?.clientHeight))  })
      const filteredPayload = payload.filter((item: any) => item.type !== "none")
      const paddingLeft =    legendPosition === "left" && yAxisWidth ? yAxisWidth - 8 : 0
      return (    <div      style={{ paddingLeft: paddingLeft }}      ref={legendRef}      className={cx(        "flex items-center",        { "justify-center": legendPosition === "center" },        {          "justify-start": legendPosition === "left",        },        { "justify-end": legendPosition === "right" },      )}    >      <Legend        categories={filteredPayload.map((entry: any) => entry.value)}        colors={filteredPayload.map((entry: any) =>          categoryColors.get(entry.value),        )}        onClickLegendItem={onClick}        activeLegend={activeLegend}        enableLegendSlider={enableLegendSlider}      />    </div>  )}
    //#region Tooltip
    type TooltipProps = Pick<ChartTooltipProps, "active" | "payload" | "label">
    type PayloadItem = {  category: string  value: number  index: string  color: AvailableChartColorsKeys  type?: string  payload: any}
    interface ChartTooltipProps {  active: boolean | undefined  payload: PayloadItem[]  label: string  valueFormatter: (value: number) => string}
    const ChartTooltip = ({  active,  payload,  label,  valueFormatter,}: ChartTooltipProps) => {  if (active && payload && payload.length) {    return (      <div        className={cx(          // base          "rounded-md border text-sm shadow-md",          // border color          "border-gray-200 dark:border-gray-800",          // background color          "bg-white dark:bg-gray-950",        )}      >        <div className={cx("border-b border-inherit px-4 py-2")}>          <p            className={cx(              // base              "font-medium",              // text color              "text-gray-900 dark:text-gray-50",            )}          >            {label}          </p>        </div>        <div className={cx("space-y-1 px-4 py-2")}>          {payload.map(({ value, category, color }, index) => (            <div              key={`id-${index}`}              className="flex items-center justify-between space-x-8"            >              <div className="flex items-center space-x-2">                <span                  aria-hidden="true"                  className={cx(                    "size-2 shrink-0 rounded-sm",                    getColorClassName(color, "bg"),                  )}                />                <p                  className={cx(                    // base                    "whitespace-nowrap text-right",                    // text color                    "text-gray-700 dark:text-gray-300",                  )}                >                  {category}                </p>              </div>              <p                className={cx(                  // base                  "whitespace-nowrap text-right font-medium tabular-nums",                  // text color                  "text-gray-900 dark:text-gray-50",                )}              >                {valueFormatter(value)}              </p>            </div>          ))}        </div>      </div>    )  }  return null}
    //#region BarChart
    type BaseEventProps = {  eventType: "category" | "bar"  categoryClicked: string  [key: string]: number | string}
    type BarChartEventProps = BaseEventProps | null | undefined
    interface BarChartProps extends React.HTMLAttributes<HTMLDivElement> {  data: Record<string, any>[]  index: string  categories: string[]  colors?: AvailableChartColorsKeys[]  valueFormatter?: (value: number) => string  startEndOnly?: boolean  showXAxis?: boolean  showYAxis?: boolean  showGridLines?: boolean  yAxisWidth?: number  intervalType?: "preserveStartEnd" | "equidistantPreserveStart"  showTooltip?: boolean  showLegend?: boolean  autoMinValue?: boolean  minValue?: number  maxValue?: number  allowDecimals?: boolean  onValueChange?: (value: BarChartEventProps) => void  enableLegendSlider?: boolean  tickGap?: number  barCategoryGap?: string | number  xAxisLabel?: string  yAxisLabel?: string  layout?: "vertical" | "horizontal"  type?: "default" | "stacked" | "percent"  legendPosition?: "left" | "center" | "right"  tooltipCallback?: (tooltipCallbackContent: TooltipProps) => void  customTooltip?: React.ComponentType<TooltipProps>}
    const BarChart = React.forwardRef<HTMLDivElement, BarChartProps>(  (props, forwardedRef) => {    const {      data = [],      categories = [],      index,      colors = AvailableChartColors,      valueFormatter = (value: number) => value.toString(),      startEndOnly = false,      showXAxis = true,      showYAxis = true,      showGridLines = true,      yAxisWidth = 56,      intervalType = "equidistantPreserveStart",      showTooltip = true,      showLegend = true,      autoMinValue = false,      minValue,      maxValue,      allowDecimals = true,      className,      onValueChange,      enableLegendSlider = false,      barCategoryGap,      tickGap = 5,      xAxisLabel,      yAxisLabel,      layout = "horizontal",      type = "default",      legendPosition = "right",      tooltipCallback,      customTooltip,      ...other    } = props    const CustomTooltip = customTooltip    const paddingValue =      (!showXAxis && !showYAxis) || (startEndOnly && !showYAxis) ? 0 : 20    const [legendHeight, setLegendHeight] = React.useState(60)    const [activeLegend, setActiveLegend] = React.useState<string | undefined>(      undefined,    )    const categoryColors = constructCategoryColors(categories, colors)    const [activeBar, setActiveBar] = React.useState<any | undefined>(undefined)    const yAxisDomain = getYAxisDomain(autoMinValue, minValue, maxValue)    const hasOnValueChange = !!onValueChange    const stacked = type === "stacked" || type === "percent"
        const prevActiveRef = React.useRef<boolean | undefined>(undefined)    const prevLabelRef = React.useRef<string | undefined>(undefined)
        function valueToPercent(value: number) {      return `${(value * 100).toFixed(0)}%`    }
        function onBarClick(data: any, _: any, event: React.MouseEvent) {      event.stopPropagation()      if (!onValueChange) return      if (deepEqual(activeBar, { ...data.payload, value: data.value })) {        setActiveLegend(undefined)        setActiveBar(undefined)        onValueChange?.(null)      } else {        setActiveLegend(data.tooltipPayload?.[0]?.dataKey)        setActiveBar({          ...data.payload,          value: data.value,        })        onValueChange?.({          eventType: "bar",          categoryClicked: data.tooltipPayload?.[0]?.dataKey,          ...data.payload,        })      }    }
        function onCategoryClick(dataKey: string) {      if (!hasOnValueChange) return      if (dataKey === activeLegend && !activeBar) {        setActiveLegend(undefined)        onValueChange?.(null)      } else {        setActiveLegend(dataKey)        onValueChange?.({          eventType: "category",          categoryClicked: dataKey,        })      }      setActiveBar(undefined)    }
        return (      <div        ref={forwardedRef}        className={cx("h-80 w-full", className)}        tremor-id="tremor-raw"        {...other}      >        <ResponsiveContainer>          <RechartsBarChart            data={data}            onClick={              hasOnValueChange && (activeLegend || activeBar)                ? () => {                    setActiveBar(undefined)                    setActiveLegend(undefined)                    onValueChange?.(null)                  }                : undefined            }            margin={{              bottom: xAxisLabel ? 30 : undefined,              left: yAxisLabel ? 20 : undefined,              right: yAxisLabel ? 5 : undefined,              top: 5,            }}            stackOffset={type === "percent" ? "expand" : undefined}            layout={layout}            barCategoryGap={barCategoryGap}          >            {showGridLines ? (              <CartesianGrid                className={cx("stroke-gray-200 stroke-1 dark:stroke-gray-800")}                horizontal={layout !== "vertical"}                vertical={layout === "vertical"}              />            ) : null}            <XAxis              hide={!showXAxis}              tick={{                transform:                  layout !== "vertical" ? "translate(0, 6)" : undefined,              }}              fill=""              stroke=""              className={cx(                // base                "text-xs",                // text fill                "fill-gray-500 dark:fill-gray-500",                { "mt-4": layout !== "vertical" },              )}              tickLine={false}              axisLine={false}              minTickGap={tickGap}              {...(layout !== "vertical"                ? {                    padding: {                      left: paddingValue,                      right: paddingValue,                    },                    dataKey: index,                    interval: startEndOnly ? "preserveStartEnd" : intervalType,                    ticks: startEndOnly                      ? [data[0][index], data[data.length - 1][index]]                      : undefined,                  }                : {                    type: "number",                    domain: yAxisDomain as AxisDomain,                    tickFormatter:                      type === "percent" ? valueToPercent : valueFormatter,                    allowDecimals: allowDecimals,                  })}            >              {xAxisLabel && (                <Label                  position="insideBottom"                  offset={-20}                  className="fill-gray-800 text-sm font-medium dark:fill-gray-200"                >                  {xAxisLabel}                </Label>              )}            </XAxis>            <YAxis              width={yAxisWidth}              hide={!showYAxis}              axisLine={false}              tickLine={false}              fill=""              stroke=""              className={cx(                // base                "text-xs",                // text fill                "fill-gray-500 dark:fill-gray-500",              )}              tick={{                transform:                  layout !== "vertical"                    ? "translate(-3, 0)"                    : "translate(0, 0)",              }}              {...(layout !== "vertical"                ? {                    type: "number",                    domain: yAxisDomain as AxisDomain,                    tickFormatter:                      type === "percent" ? valueToPercent : valueFormatter,                    allowDecimals: allowDecimals,                  }                : {                    dataKey: index,                    ticks: startEndOnly                      ? [data[0][index], data[data.length - 1][index]]                      : undefined,                    type: "category",                    interval: "equidistantPreserveStart",                  })}            >              {yAxisLabel && (                <Label                  position="insideLeft"                  style={{ textAnchor: "middle" }}                  angle={-90}                  offset={-15}                  className="fill-gray-800 text-sm font-medium dark:fill-gray-200"                >                  {yAxisLabel}                </Label>              )}            </YAxis>            <Tooltip              wrapperStyle={{ outline: "none" }}              isAnimationActive={true}              animationDuration={100}              cursor={{ fill: "#d1d5db", opacity: "0.15" }}              offset={20}              position={{                y: layout === "horizontal" ? 0 : undefined,                x: layout === "horizontal" ? undefined : yAxisWidth + 20,              }}              content={({ active, payload, label }) => {                const cleanPayload: TooltipProps["payload"] = payload                  ? payload.map((item: any) => ({                      category: item.dataKey,                      value: item.value,                      index: item.payload[index],                      color: categoryColors.get(                        item.dataKey,                      ) as AvailableChartColorsKeys,                      type: item.type,                      payload: item.payload,                    }))                  : []
                    if (                  tooltipCallback &&                  (active !== prevActiveRef.current ||                    label !== prevLabelRef.current)                ) {                  tooltipCallback({ active, payload: cleanPayload, label })                  prevActiveRef.current = active                  prevLabelRef.current = label                }
                    return showTooltip && active ? (                  CustomTooltip ? (                    <CustomTooltip                      active={active}                      payload={cleanPayload}                      label={label}                    />                  ) : (                    <ChartTooltip                      active={active}                      payload={cleanPayload}                      label={label}                      valueFormatter={valueFormatter}                    />                  )                ) : null              }}            />            {showLegend ? (              <RechartsLegend                verticalAlign="top"                height={legendHeight}                content={({ payload }) =>                  ChartLegend(                    { payload },                    categoryColors,                    setLegendHeight,                    activeLegend,                    hasOnValueChange                      ? (clickedLegendItem: string) =>                          onCategoryClick(clickedLegendItem)                      : undefined,                    enableLegendSlider,                    legendPosition,                    yAxisWidth,                  )                }              />            ) : null}            {categories.map((category) => (              <Bar                className={cx(                  getColorClassName(                    categoryColors.get(category) as AvailableChartColorsKeys,                    "fill",                  ),                  onValueChange ? "cursor-pointer" : "",                )}                key={category}                name={category}                type="linear"                dataKey={category}                stackId={stacked ? "stack" : undefined}                isAnimationActive={false}                fill=""                shape={(props: any) =>                  renderShape(props, activeBar, activeLegend, layout)                }                onClick={onBarClick}              />            ))}          </RechartsBarChart>        </ResponsiveContainer>      </div>    )  },)
    BarChart.displayName = "BarChart"
    export { BarChart, type BarChartEventProps, type TooltipProps }
    

Example with Axis Labels

Example with different types

type="default"

type="stacked"

type="percent"

Example with vertical layout

Example with onValueChange

When you add onValueChange to the BarChart, the bars become clickable.

null

Example with startEndOnly, custom yAxisWidth, no legend, and no tooltip

Example with grouped data

Special Example with conditional RenderShape color

null

Example with tooltipCallback

Revenue by month

$4,900

Example with customTooltip

API Reference: BarChart

data
Required
Record<string, any>[]
Data used to display the chart.
index
Required
string[]
Key of the data object to map the data to the x axis.

Default: []

categories
Required
string[]
Select the categories from your data. Also used to populate the legend and toolip.

Default: []

colors
AvailableChartColorsKeys[]
Change the colors of the categories. To add, update, or remove the colors, edit the 'chartColors' array in your chartUtils.ts file. The AvailableChartColorsKeys will be automatically updated.

Default: AvailableChartColors, which are by default: 'blue' | 'emerald' | 'violet' | 'amber' | 'gray' | 'cyan' | 'pink' | 'lime' | 'fuchsia'

type
'default' | 'stacked' | 'percent'
Select how bars are positioned relative to each other.

Default: 'default'

valueFormatter
(value: number) => string
Controls the text formatting for the y-axis values. Also used in the Tooltip.
startEndOnly
boolean
Show only the first and last elements in the x-axis.

Default: false

showXAxis
boolean
Controls the visibility of the X axis.

Default: true

showYAxis
boolean
Controls the visibility of the Y axis.

Default: true

yAxisWidth
number
Controls the width of the y-axis.

Default: 56

showGridLines
boolean
Controls the visibility of the gridlines within the plotted area.

Default: true

intervalType
equidistantPreserveStart | preserveStartEnd
Controls the interval logic of the X axis and how ticks and labels are placed.

Default: equidistantPreserveStart

showTooltip
boolean
Controls the visibility of the tooltip.

Default: true

showLegend
boolean
Controls the visibility of the legend.

Default: true

autoMinValue
boolean
Adjusts the minimum value in relation to the magnitude of the data.

Default: false

minValue
number
Sets the minimum value of the shown chart data.
maxValue
number
Sets the maximum value of the shown chart data.
allowDecimals
boolean
Controls if the ticks of a numeric axis are displayed as decimals or not.

Default: true

onValueChange
(value: EventProps) => void
Callback function for when the value of the component changes.
enableLegendSlider
boolean
Adds a slider functionality to the legend instead of wrapping the legend items.

Default: false

tickGap
number
Sets the minimum gap between two adjacent labels.

Default: 5

barCategoryGap
Percentage | number
The gap between two bar categories, which can be a percent value (string) or a fixed value.

Default: 10%

xAxisLabel
string
Add a label to the x-axis.
yAxisLabel
string
Add a label to the y-axis.
layout
"vertical" | "horizontal"
Controls stacking direction of the bars.

Default: "horizontal

legendPosition
'left' | 'center' | 'right'
Controls the horizontal alignment of the legend.

Default: 'right'

tooltipCallback
(tooltipCallbackContent: TooltipProps) => void
Callback function that returns the active, payload, when the tooltip changes.
customTooltip
React.ComponentType<TooltipProps>
Render a custom tooltip component.