Beta

Visualization

BarList

Horizontal bars with a label inside.

    843

    384

    108

    46

    3

    Installation

    1. 1

      Add component:

      Copy and paste the code into your project’s component directory. Do not forget to update the import paths.
      // Tremor Raw BarList [v0.1.0]
      import React from "react"
      import { cx, focusRing } from "@/lib/utils"
      type Bar<T> = T & {  key?: string  href?: string  value: number  name: string}
      interface BarListProps<T = unknown>  extends React.HTMLAttributes<HTMLDivElement> {  data: Bar<T>[]  valueFormatter?: (value: number) => string  showAnimation?: boolean  onValueChange?: (payload: Bar<T>) => void  sortOrder?: "ascending" | "descending" | "none"}
      function BarListInner<T>(  {    data = [],    valueFormatter = (value) => value.toString(),    showAnimation = false,    onValueChange,    sortOrder = "descending",    className,    ...props  }: BarListProps<T>,  forwardedRef: React.ForwardedRef<HTMLDivElement>,) {  const Component = onValueChange ? "button" : "div"  const sortedData = React.useMemo(() => {    if (sortOrder === "none") {      return data    }    return [...data].sort((a, b) => {      return sortOrder === "ascending" ? a.value - b.value : b.value - a.value    })  }, [data, sortOrder])
        const widths = React.useMemo(() => {    const maxValue = Math.max(...sortedData.map((item) => item.value), 0)    return sortedData.map((item) =>      item.value === 0 ? 0 : Math.max((item.value / maxValue) * 100, 2),    )  }, [sortedData])
        const rowHeight = "h-8"
        return (    <div      ref={forwardedRef}      className={cx("flex justify-between space-x-6", className)}      aria-sort={sortOrder}      {...props}    >      <div className="relative w-full space-y-1.5">        {sortedData.map((item, index) => (          <Component            key={item.key ?? item.name}            onClick={() => {              onValueChange?.(item)            }}            className={cx(              // base              "group w-full rounded",              // focus              focusRing,              onValueChange                ? [                    "!-m-0 cursor-pointer",                    // hover                    "hover:bg-gray-50 hover:dark:bg-gray-900",                  ]                : "",            )}          >            <div              className={cx(                // base                "flex items-center rounded transition-all",                rowHeight,                // background color                "bg-blue-200 dark:bg-blue-900",                onValueChange                  ? "group-hover:bg-blue-300 group-hover:dark:bg-blue-800"                  : "",                // margin and duration                {                  "mb-0": index === sortedData.length - 1,                  "duration-800": showAnimation,                },              )}              style={{ width: `${widths[index]}%` }}            >              <div className={cx("absolute left-2 flex max-w-full pr-2")}>                {item.href ? (                  <a                    href={item.href}                    className={cx(                      // base                      "truncate whitespace-nowrap rounded text-sm",                      // text color                      "text-gray-900 dark:text-gray-50",                      // hover                      "hover:underline hover:underline-offset-2",                      // focus                      focusRing,                    )}                    target="_blank"                    rel="noreferrer"                    onClick={(event) => event.stopPropagation()}                  >                    {item.name}                  </a>                ) : (                  <p                    className={cx(                      // base                      "truncate whitespace-nowrap text-sm",                      // text color                      "text-gray-900 dark:text-gray-50",                    )}                  >                    {item.name}                  </p>                )}              </div>            </div>          </Component>        ))}      </div>      <div>        {sortedData.map((item, index) => (          <div            key={item.key ?? item.name}            className={cx(              "flex items-center justify-end",              rowHeight,              index === sortedData.length - 1 ? "mb-0" : "mb-1.5",            )}          >            <p              className={cx(                // base                "truncate whitespace-nowrap text-sm leading-none",                // text color                "text-gray-900 dark:text-gray-50",              )}            >              {valueFormatter(item.value)}            </p>          </div>        ))}      </div>    </div>  )}
      BarListInner.displayName = "BarList"
      const BarList = React.forwardRef(BarListInner) as <T>(  p: BarListProps<T> & { ref?: React.ForwardedRef<HTMLDivElement> },) => ReturnType<typeof BarListInner>
      export { BarList, type BarListProps }

    Example

    To render a BarList you need to pass an array to the data prop.

    /home

    /documentation

    /blocks

    /imprint

    /cancellation

    843

    384

    108

    46

    3

    Example with sortOrder

    To change the sort order, use the sortOrder prop.

    /cancellation

    /imprint

    /blocks

    /documentation

    /home

    3

    46

    108

    384

    843

    Example with href and valueFormatter

    When you add a href to the passed array, the labels become anchor tags.

    843 Visitors

    384 Visitors

    108 Visitors

    46 Visitors

    3 Visitors

    Example with onValueChange

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

    843

    384

    108

    46

    3

    Click on a bar

    Example with onValueChange and href

    It is also possible to combine href and onValueChange.

    API Reference: BarList

    data
    Required
    Bar<T>[]
    Array of objects, with each object containing a value (number), name (string). Here are the detailed types for Bar<T> = T &
    • value: number
    • name: string
    • key?: string
    • href?: string
    onValueChange
    (payload: Bar<T>) => void;
    Handler that is called when the value changes.
    showAnimation
    boolean
    Sets an animation to the chart when it is loaded.

    Default: false

    sortOrder
    "ascending" | "descending" | "none"
    Change the sort order.

    Default: desc

    valueFormatter
    (value: number) => string
    Controls the text formatting for the y-axis values.