Skip to content
Domphy

chartBarActive

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

Props

PropTypeDescription
dataChartBarCategoryPoint[]
seriesLabelstring
seriesColorThemeColor
activeIndexnumberIndex of the bar rendered with the dashed-outline "active" treatment.
titlestring
subtitlestring
trendTextstring
trendDirectionChartTrendDirection
captionTextstring
heightnumber
Implementation notes

A designated bar (activeIndex, default 2) is emphasized by a dashed-stroke rounded-rect SVG overlay (chartBarActiveOverlay) drawn with the same public scale factories as the real chart, positioned pixel-exact over that bar. The standard hover-tooltip cursor rectangle is disabled via axisPointer:'none' as specified. Two real gaps versus the spec, both from BarRenderer (packages/chart/src/gl/BarRenderer.ts) reading only itemStyle.color per data item and nothing else: (1) the spec's '~0.8 fill opacity on the active bar, other bars comparatively flat/muted' cannot be reproduced — there is no per-item opacity hook, so all bars render at full, equal opacity and only the dashed outline distinguishes the active one. (2) the dashed stroke is a separate overlay rect, not a stroke drawn on the bar's own WebGL geometry (no borderWidth/borderType/borderColor support), so it can visually drift by a pixel or two on rapid container resizes between the chart's own render pass and the overlay's ResizeObserver-driven redraw. Click/hover-to-reassign which bar is active (mentioned in the spec as an optional 'could reassign' extension, not the reference demo's actual fixed-default behavior) was not wired up — activeIndex is a static prop evaluated once per render, matching the literal 'fixed bar marked active by default' behavior the spec describes as required. Direct-source-diff fix (2026-07-05): Was rendered as a single uniform hue — upstream is multi-color (each bar its own chart-N accent) with the active bar's dashed outline drawn in that bar's own color, not a fixed accent. Fixed to per-item coloring.

Status: partial · Reference: shadcn/ui original

// shadcn/ui "chart-bar" (active recipe) — clean-room reimplementation.
//
// A vertical multi-color bar chart (each bar carries its own accent color)
// where one pre-selected bar is deliberately emphasized with a bold dashed
// outline in that bar's own color (rather than relying on hover), and the
// standard hover-tooltip cursor rectangle is disabled so the dashed bar
// reads as a persistent "selected" state.
//
// Implemented purely from the block's public functional/visual spec — no
// upstream shadcn/ui source was viewed or copied.

import type { ChartOption, TooltipParams } from "@domphy/chart";
import type { DomphyElement } from "@domphy/core";
import {
  type ChartBarCategoryPoint,
  type ChartBarGrid,
  type ChartTrendDirection,
  chartBarActiveOverlay,
  chartBarCardShell,
  chartBarCategoryXAxis,
  chartBarColorHex,
  chartBarFrame,
  chartBarHiddenValueYAxis,
  chartBarSeriesColor,
  chartBarTooltipRow,
  chartBarTrendFooter,
  chartBarValueDomain,
} from "./chart-bar-shared.js";

export interface ChartBarActiveProps {
  data?: ChartBarCategoryPoint[];
  seriesLabel?: string;
  /** Fallback bar color for data items without their own — a theme role
   * (resolved at shift-9) or literal ramp hex. */
  seriesColor?: string;
  /** Index of the bar rendered with the dashed-outline "active" treatment. */
  activeIndex?: number;
  title?: string;
  subtitle?: string;
  trendText?: string;
  trendDirection?: ChartTrendDirection;
  captionText?: string;
  height?: number;
}

const GRID: ChartBarGrid = { left: 8, right: 8, top: 16, bottom: 32 };

// The active recipe carries its OWN dataset — distinct from the mixed recipe's
// shared CHART_BAR_BROWSER_DATA — so the pre-selected bar at index 2 (Firefox)
// is the tallest peak, giving the dashed "active" outline something prominent
// to sit on. Per-browser colors follow the same single-hue ramp as the mixed
// recipe (upstream colors each bar from the SAME chart ramp, chart-1 … chart-5).
const CHART_BAR_ACTIVE_DATA: ChartBarCategoryPoint[] = [
  { category: "Chrome", value: 187, color: chartBarSeriesColor(0).hex },
  { category: "Safari", value: 200, color: chartBarSeriesColor(1).hex },
  { category: "Firefox", value: 275, color: chartBarSeriesColor(2).hex },
  { category: "Edge", value: 173, color: chartBarSeriesColor(3).hex },
  { category: "Other", value: 90, color: chartBarSeriesColor(4).hex },
];

/**
 * shadcn/ui "chart-bar" active recipe — a fixed bar carries a dashed-stroke
 * "selected" outline instead of relying on hover. Call with no arguments for
 * a working demo.
 */
function chartBarActive(props: ChartBarActiveProps = {}): DomphyElement<"div"> {
  const {
    data = CHART_BAR_ACTIVE_DATA,
    seriesLabel = "Visitors",
    seriesColor = chartBarSeriesColor(0).hex,
    activeIndex = 2,
    title = "Bar Chart - Active",
    subtitle = "January - June 2026",
    trendText = "Trending up by 5.2% this month",
    trendDirection = "up",
    captionText = "Showing total visitors by browser",
    height = 64,
  } = props;

  const categories = data.map((point) => point.category);
  const values = data.map((point) => point.value);
  const valueDomain = chartBarValueDomain(values);
  const clampedActiveIndex = Math.max(
    0,
    Math.min(data.length - 1, activeIndex),
  );
  const barColor = (index: number): string => data[index]?.color ?? seriesColor;

  const option: ChartOption = {
    tooltip: {
      trigger: "axis",
      // The standard shaded cursor rectangle is turned off entirely so the
      // pre-set active bar's dashed outline is the only visual emphasis.
      axisPointer: { type: "none" },
      // Upstream renders this recipe's tooltip with <ChartTooltipContent
      // hideLabel /> — the category header (e.g. "Firefox") is suppressed, so
      // only the single series dot + "Visitors" + value row shows. The dot
      // re-resolves the hovered bar's own ramp color (the engine's param
      // `color` follows its multi-hue rotation palette instead).
      formatter: chartBarActiveTooltipFormatter((index) => barColor(index)),
    },
    xAxis: chartBarCategoryXAxis(categories),
    yAxis: chartBarHiddenValueYAxis({
      min: valueDomain[0],
      max: valueDomain[1],
    }),
    grid: GRID,
    // Every bar carries its own accent color — upstream's active recipe is a
    // multi-color chart, not a single-hue one; one bar is then singled out by
    // the dashed overlay below (drawn in that same bar's color).
    series: [
      {
        type: "bar",
        name: seriesLabel,
        data: data.map((point, index) => ({
          value: point.value,
          itemStyle: { color: chartBarColorHex(barColor(index)) },
        })),
      },
    ],
  };

  return chartBarCardShell({
    title,
    subtitle,
    content: {
      div: [
        chartBarFrame(option, {
          height,
          overlays: [
            chartBarActiveOverlay({
              categories,
              values,
              valueDomain,
              grid: GRID,
              activeIndex: clampedActiveIndex,
              color: barColor(clampedActiveIndex),
            }),
          ],
        }),
      ],
    },
    footer: chartBarTrendFooter({
      trendText,
      direction: trendDirection,
      captionText,
    }),
  });
}

function escapeTooltipHtml(text: string): string {
  return text
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;");
}

// hideLabel formatter: omits the category header line, printing only the
// single series' color dot + name + value (mirrors chart-bar-default's
// chartBarDefaultTooltipFormatter and upstream's <ChartTooltipContent
// hideLabel />).
function chartBarActiveTooltipFormatter(
  barColorAt: (dataIndex: number) => string,
): (parametersInput: TooltipParams | TooltipParams[]) => string {
  return (parametersInput) => {
    const parameters = Array.isArray(parametersInput)
      ? parametersInput
      : [parametersInput];
    if (parameters.length === 0) return "";
    const item = parameters[0];
    const dot = `<span style="display:inline-block;width:8px;height:8px;border-radius:50%;background:${chartBarColorHex(barColorAt(item.dataIndex))};margin-right:6px;"></span>`;
    const label = escapeTooltipHtml(String(item.seriesName ?? item.name ?? ""));
    const value = escapeTooltipHtml(String(item.value ?? ""));
    return chartBarTooltipRow(dot, label, value);
  };
}

export { chartBarActive };

← Back to shadcn/ui catalog