807
Sponsor

Dither Bar Chart

Dithered grouped, stacked, and percent bar charts with terminal-native textures and interaction

Terminal

Installation

$ pnpm dlx shadcn@latest add @termcn/opentui/dither-bar-chart

Usage

import {
  Bar,
  BarChart,
  Grid,
  Legend,
  Tooltip,
  XAxis,
  YAxis,
} from "@/components/ui/dither-bar-chart";
import type { ChartConfig } from "@/components/ui/dither-bar-chart";
const data = [
  { month: "Jan", direct: 34, search: 18 },
  { month: "Feb", direct: 47, search: 24 },
  { month: "Mar", direct: 42, search: 29 },
];
 
const config = {
  direct: { color: "green", label: "Direct" },
  search: { color: "purple", label: "Search" },
} satisfies ChartConfig;
 
<BarChart config={config} data={data} stackType="stacked" width={56}>
  <Grid horizontal />
  <XAxis dataKey="month" />
  <YAxis tickCount={4} />
  <Bar dataKey="direct" variant="gradient" />
  <Bar dataKey="search" variant="hatched" />
  <Legend align="left" />
  <Tooltip labelKey="month" />
</BarChart>;

Examples

Bar textures

Set variant on a Bar to render gradient, dotted, hatched, or solid cells.

Terminal
import { Bar, BarChart } from "@/components/ui/dither-bar-chart";
import type { ChartConfig } from "@/components/ui/dither-bar-chart";

const data = [{ value: 18 }, { value: 32 }, { value: 26 }, { value: 43 }];

const config = {
  value: { color: "orange", label: "Deploys" },
} satisfies ChartConfig;

const variants = ["gradient", "dotted", "hatched", "solid"] as const;

export function DitherBarChartVariants() {
  return (
    <box flexDirection="column" gap={1}>
      {[variants.slice(0, 2), variants.slice(2)].map((row, rowIndex) => (
        <box gap={2} key={rowIndex}>
          {row.map((variant) => (
            <box key={variant}>
              <BarChart
                animate={false}
                config={config}
                data={data}
                height={6}
                interactive={false}
                title={variant}
                width={27}
              >
                <Bar dataKey="value" variant={variant} />
              </BarChart>
            </box>
          ))}
        </box>
      ))}
    </box>
  );
}

Stacking modes

Switch between cumulative stacks and normalized percent stacks with stackType.

Terminal
import { Bar, BarChart } from "@/components/ui/dither-bar-chart";
import type { ChartConfig } from "@/components/ui/dither-bar-chart";

const data = [
  { direct: 24, search: 18 },
  { direct: 35, search: 22 },
  { direct: 31, search: 28 },
  { direct: 46, search: 25 },
];

const config = {
  direct: { color: "green", label: "Direct" },
  search: { color: "purple", label: "Search" },
} satisfies ChartConfig;

export function DitherBarChartStacking() {
  return (
    <box gap={2}>
      {(["stacked", "percent"] as const).map((stackType) => (
        <box key={stackType}>
          <BarChart
            animate={false}
            config={config}
            data={data}
            height={7}
            interactive={false}
            stackType={stackType}
            title={stackType}
            width={29}
          >
            <Bar dataKey="direct" variant="gradient" />
            <Bar dataKey="search" variant="hatched" />
          </BarChart>
        </box>
      ))}
    </box>
  );
}

API Reference

PropTypeDefault
dataTData[]required
configChartConfigrequired
widthnumber56
heightnumber12
stackType"default" | "stacked" | "percent""default"
bloom"off" | "low" | "high" | "aura" | BloomConfig"off"
interactivebooleantrue
noColorbooleanfalse
screenReaderModebooleanfalse

Arrow keys or H/J/K/L navigate chart state; Enter selects clickable series and Escape clears the active point.