MetricUIMetricUI
UI

DrillDown.Root

Provider wrapper that manages the drill-down stack and renders the overlay panel. Wrap your dashboard (or a section) in DrillDown.Root to enable drill-down on child components.

import { DrillDown } from "metricui";

Overview

The DrillDown system is composed of three pieces: a DrillDown.Root wrapper that provides context and renders the overlay portal, a drillDown prop on chart components that wires up click-to-drill, and hooks ( useDrillDown, useDrillDownAction) for programmatic control.

import { DrillDown, useDrillDownAction } from "metricui";

function Dashboard() {
  return (
    <DrillDown.Root>
      <BarChart
        data={data}
        index="region"
        categories={["revenue"]}
        drillDown          // true = auto-table
        tooltipHint        // "Click to drill down"
      />
    </DrillDown.Root>
  );
}

Zero-Config DrillDown

Pass drillDown={true} to any chart. Clicking a bar, slice, or point opens a slide-over with an auto-generated detail table showing filtered rows, summary KPIs, and search.

<DrillDown.Root>
  <BarChart
    data={revenueByRegion}
    index="region"
    categories={["revenue"]}
    title="Revenue by Region"
    drillDown
    tooltipHint
  />
</DrillDown.Root>

Custom Content

Pass a function to drillDown to render custom content. The function receives the click event and returns a ReactNode. Use MetricGrid, KpiCards, DataTable, or any component inside.

<DrillDown.Root>
  <BarChart
    data={revenueByRegion}
    index="region"
    categories={["revenue", "accounts"]}
    title="Revenue by Region"
    drillDown={(event) => {
      const regionAccounts = accounts.filter(
        (a) => a.region === event.indexValue,
      );
      return (
        <MetricGrid>
          <KpiCard title="Accounts" value={regionAccounts.length} />
          <KpiCard title="Total Revenue"
            value={regionAccounts.reduce((s, a) => s + a.revenue, 0)}
            format="currency"
          />
          <DataTable
            data={regionAccounts}
            columns={[
              { key: "account", header: "Account" },
              { key: "plan", header: "Plan" },
              { key: "revenue", header: "Revenue", format: "currency" },
            ]}
            dense
          />
        </MetricGrid>
      );
    }}
    tooltipHint="Click to view accounts"
  />
</DrillDown.Root>

Nested Drills

Drill levels stack up to 4 deep. Inside drill content, use useDrillDownAction() to open sub-drills. Breadcrumbs appear automatically for navigation, and Escape goes back one level.

function NestedDrill() {
  const openDrill = useDrillDownAction();

  return (
    <BarChart
      data={revenueByRegion}
      index="region"
      categories={["revenue"]}
      drillDown={(event) => {
        const regionAccounts = accounts.filter(
          (a) => a.region === event.indexValue,
        );
        return (
          <div className="space-y-4">
            {regionAccounts.map((acct) => (
              <button
                key={acct.account}
                onClick={() =>
                  openDrill(
                    { title: acct.account, field: "account", value: acct.account },
                    <KpiCard title="Revenue" value={acct.revenue} format="currency" />,
                  )
                }
              >
                {acct.account}
              </button>
            ))}
          </div>
        );
      }}
    />
  );
}

Reactive Content (renderContent)

DrillDown.Root accepts a renderContent prop — a function called on every render with the active trigger. This is useful when the drill content should react to live data changes (e.g., real-time dashboards). Return null to fall through to the stored content.

<DrillDown.Root
  renderContent={(trigger) => {
    const region = String(trigger.value);
    const regionAccounts = accounts.filter((a) => a.region === region);
    const totalRevenue = regionAccounts.reduce((s, a) => s + a.revenue, 0);
    return (
      <MetricGrid>
        <KpiCard title="Region" value={region} />
        <KpiCard title="Total Revenue" value={totalRevenue} format="currency" />
        <KpiCard title="Accounts" value={regionAccounts.length} format="number" />
      </MetricGrid>
    );
  }}
>
  <BarChart
    data={liveData}
    index="region"
    categories={["revenue"]}
    drillDown
    tooltipHint
  />
</DrillDown.Root>

Hooks

Two hooks provide full programmatic control over the drill-down system.

useDrillDownAction()

Returns an openDrill(trigger, content) function. Use it in click handlers, buttons, or any event to imperatively open a drill level.

useDrillDown()

Returns the full drill-down state: { isOpen, depth, breadcrumbs, back, close, goTo, open, activeContent, activeTrigger }. Use it to build custom navigation, conditionally render UI based on drill state, or close drills programmatically.

useDrillDown() state

isOpen: false

depth: 0

breadcrumbs: []

import { useDrillDown, useDrillDownAction } from "metricui";

function MyComponent() {
  const drill = useDrillDown();
  const openDrill = useDrillDownAction();

  return (
    <div>
      <button onClick={() =>
        openDrill(
          { title: "US Details", field: "region", value: "US" },
          <KpiCard title="Revenue" value={142000} format="currency" />,
        )
      }>
        Open US drill
      </button>

      <p>isOpen: {String(drill?.isOpen)}</p>
      <p>depth: {drill?.depth}</p>
      <p>breadcrumbs: [{drill?.breadcrumbs.map(b => b.title).join(", ")}]</p>
    </div>
  );
}

Tooltip Hints

The tooltipHint prop adds an action hint to chart tooltips so users know they can click to drill. Pass truefor the default "Click to drill down" text, or pass a custom string.

{/* Default hint */}
<BarChart drillDown tooltipHint />

{/* Custom hint text */}
<BarChart drillDown tooltipHint="Click to see breakdown" />

Props

PropTypeDescription
children*
React.ReactNode

Dashboard content that contains components with drillDown props.

defaultMode
DrillDownMode

Default presentation mode for drill panels. "slide-over" slides from the right, full height. "modal" renders centered and compact. Individual components can override via drillDownMode.

maxDepth
number

Maximum nesting depth for drill-down navigation.

className
string

Additional CSS class names for the overlay container.

Notes

  • DrillDown.Root must wrap any components that use the drillDown prop.
  • drillDown={true} auto-generates a summary KPI row + filtered DataTable from the component's source data — zero config needed.
  • drillDown={(event) => <CustomContent />} gives full control over what appears in the panel.
  • Two presentation modes: 'slide-over' (default, full height from right) and 'modal' (centered, compact).
  • Navigation: breadcrumbs for nested drills (up to 4 levels), back arrow, close X, Escape key, backdrop click.
  • When both drillDown and crossFilter are set on the same component, drillDown wins.
  • useDrillDown() returns { isOpen, breadcrumbs, depth, back, close } for reading state in custom components.
  • useDrillDownAction() returns openDrill(trigger, content) for imperative use outside of chart click handlers.
  • The aiContext prop (inherited from BaseComponentProps) adds business context for AI Insights analysis. See the AI Insights guide for details.