Domphy

chartBarHorizontal

A Charts block/component from shadcn/ui — clean-room reimplemented for Domphy (see methodology). Call chartBarHorizontal() with no arguments for a working demo, or edit the code below live.

Implementation notes

Same monthly dataset rotated into horizontal bars against a left category axis, hidden value axis. The engine's built-in axis-trigger tooltip resolves hover position by comparing mouse X against the X scale unconditionally (packages/chart/src/engine.ts bindTooltipEvents) — meaningless for horizontal bars where the category axis is Y — and there is no item-trigger hit-testing for bar series at all, so the native tooltip is disabled (tooltip: {show:false}) and replaced with a custom mouse-to-row overlay (chartBarHorizontalHoverOverlay in chart-bar-shared.ts) built with @domphy/chart's own exported scale factories (createOrdinalScale/createLinearScale) against an explicit fixed-pixel grid, so it lines up exactly with the real bars. Category (y) axes render bottom-to-top in this engine, so the data/category arrays are reversed before rendering to keep the on-screen top-to-bottom order chronological (Jan at top). Corner radius again capped at the engine's hardcoded 2px regardless of the requested [0,5,5,0] radius.

Status: ported · Reference: shadcn/ui original

// shadcn/ui "chart-bar" (horizontal recipe) — clean-room reimplementation.
//
// The same single-series monthly dataset as the default recipe, rotated so
// each month is a row with a bar extending rightward from a left category
// axis; the numeric axis is fully hidden.
//
// Implemented purely from the block's public functional/visual spec — no
// upstream shadcn/ui source was viewed or copied.

import type { DomphyElement } from "@domphy/core";
import type { ChartOption } from "@domphy/chart";
import type { ThemeColor } from "@domphy/theme";
import {
  CHART_BAR_MONTHLY_DATA,
  chartBarCardShell,
  chartBarCategoryYAxis,
  chartBarFrame,
  chartBarHiddenValueXAxis,
  chartBarHorizontalHoverOverlay,
  chartBarTrendFooter,
  chartBarValueDomain,
  type ChartBarGrid,
  type ChartBarPoint,
  type ChartTrendDirection,
} from "./chart-bar-shared.js";

export interface ChartBarHorizontalProps {
  data?: ChartBarPoint[];
  seriesLabel?: string;
  seriesColor?: ThemeColor;
  title?: string;
  subtitle?: string;
  trendText?: string;
  trendDirection?: ChartTrendDirection;
  captionText?: string;
  /** Max characters kept from each category label before truncation. */
  categoryTruncateLength?: number;
  grid?: ChartBarGrid;
  height?: number;
}

const DEFAULT_GRID: ChartBarGrid = { left: 44, right: 16, top: 8, bottom: 8 };

/**
 * shadcn/ui "chart-bar" horizontal recipe — the default recipe's dataset
 * rotated into rightward-extending rows against a left category axis. Call
 * with no arguments for a working demo.
 */
function chartBarHorizontal(props: ChartBarHorizontalProps = {}): DomphyElement<"div"> {
  const {
    data = CHART_BAR_MONTHLY_DATA,
    seriesLabel = "Desktop",
    seriesColor = "primary",
    title = "Bar Chart - Horizontal",
    subtitle = "January - June 2026",
    trendText = "Trending up by 5.2% this month",
    trendDirection = "up",
    captionText = "Showing total visitors for the last 6 months",
    categoryTruncateLength = 12,
    grid = DEFAULT_GRID,
    height = 64,
  } = props;

  // Category (y) axes render bottom-to-top — reverse the data order so the
  // on-screen reading order (top-to-bottom) stays chronological. See the
  // file-level fidelity note in chart-bar-shared.ts.
  const orderedData = [...data].reverse();
  const categories = orderedData.map((point) => point.label.slice(0, categoryTruncateLength));
  const values = orderedData.map((point) => point.value);
  const [, domainMax] = chartBarValueDomain(values);

  const option: ChartOption = {
    tooltip: { show: false },
    xAxis: chartBarHiddenValueXAxis({ min: 0, max: domainMax }),
    yAxis: chartBarCategoryYAxis(categories),
    grid,
    series: [
      {
        type: "bar",
        name: seriesLabel,
        color: seriesColor,
        itemStyle: { borderRadius: [0, 5, 5, 0] },
        data: values,
      },
    ],
  };

  return chartBarCardShell({
    title,
    subtitle,
    content: {
      div: [
        chartBarFrame(option, {
          height,
          overlays: [
            chartBarHorizontalHoverOverlay({
              categories,
              grid,
              valueLabel: (index) => String(values[index] ?? ""),
            }),
          ],
        }),
      ],
    },
    footer: chartBarTrendFooter({ trendText, direction: trendDirection, captionText }),
  });
}

export { chartBarHorizontal };

← Back to shadcn/ui catalog