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>Modal Mode
Set drillDownMode="modal" to open the drill content in a centered modal instead of the default slide-over panel. The modal is capped at 85vh height and 3xl width.
<DrillDown.Root>
<BarChart
data={revenueByRegion}
index="region"
categories={["revenue"]}
drillDown
drillDownMode="modal"
tooltipHint
/>
</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
| Prop | Type | Default | Description |
|---|---|---|---|
children* | React.ReactNode | — | Dashboard content that contains components with drillDown props. |
defaultMode | DrillDownMode | "slide-over" | 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 | 4 | 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
aiContextprop (inherited from BaseComponentProps) adds business context for AI Insights analysis. See the AI Insights guide for details.