Interactions
Visual coordination between dashboard components. Linked hover syncs crosshairs across charts. Value flash highlights data changes in real time. For click-based filtering, see Cross-Filtering in the Filtering guide.
Overview
MetricUI provides two visual interaction primitives, each opt-in and independent:
| Feature | What It Does | Trigger |
|---|---|---|
| Linked Hover | Hover a data point → crosshairs sync across all charts | Hover |
| Value Flash | Data changes → brief highlight animation on the value | Data update |
Both are purely visual — they coordinate what users see across components without touching your data. Wrap in a Provider, and the components handle the rest.
Linked Hover
Linked hover syncs hover state across all charts in a provider. Hover over “March” in an area chart, and the bar chart, line chart, and any other sibling highlights March too — synced crosshairs, synced tooltips, synced emphasis.
Try It
Hover over any chart — the other follows your cursor.
<LinkedHoverProvider>
<AreaChart
title="Revenue"
data={monthlyData}
index="month"
categories={[{ key: "revenue", format: "currency" }]}
/>
<BarChart
title="Orders"
data={monthlyData}
index="month"
categories={["orders"]}
/>
</LinkedHoverProvider>Setup
Wrap in LinkedHoverProvider. Charts inside it automatically participate — no extra prop needed:
import {
LinkedHoverProvider,
AreaChart,
BarChart,
LineChart,
} from "metricui";
function Dashboard() {
return (
<LinkedHoverProvider>
<AreaChart
title="Revenue"
data={data}
index="month"
categories={["revenue"]}
/>
<BarChart
title="Orders"
data={data}
index="month"
categories={["orders"]}
/>
</LinkedHoverProvider>
);
}Hover over any chart and the others follow. The charts share the same indexvalues (“Jan”, “Feb”, etc.), so linked hover matches by index.
Reading Hover State
Use useLinkedHover() to read hover state in custom components:
import { useLinkedHover } from "metricui";
function HoverDebug() {
const lh = useLinkedHover();
if (!lh?.hoveredIndex) return null;
return (
<div>
Hovering: {lh.hoveredIndex}
{lh.hoveredSeries && <> / Series: {lh.hoveredSeries}</>}
</div>
);
}| Property | Type | Description |
|---|---|---|
hoveredIndex | string | number | null | The x-axis value being hovered (e.g. "Mar") |
hoveredSeries | string | null | The series/category being hovered (e.g. "revenue") |
sourceId | string | undefined | Which component emitted the hover event |
setHoveredIndex | (index, sourceId?) => void | Programmatically set the hovered index |
setHoveredSeries | (seriesId, sourceId?) => void | Programmatically set the hovered series |
Value Flash
Value flash is a hook that adds a brief highlight animation when watched data changes. You choose which components flash and what data to watch — it's not automatic. Useful for real-time dashboards where individual values update via polling or websockets.
Try It
These KPI cards update every 2.5 seconds. Watch for the flash when values change.
function LiveKpi({ value, ...props }) {
const flashClass = useValueFlash(value);
return (
<div className={flashClass}>
<KpiCard value={value} {...props} />
</div>
);
}Usage
useValueFlash is a hook that returns a CSS class name. Apply it to the container you want to flash:
import { useValueFlash } from "metricui";
function LiveMetric({ value }: { value: number }) {
const flashClass = useValueFlash(value);
return (
<div className={flashClass}>
{value.toLocaleString()}
</div>
);
}The hook watches the value you pass. On the first render, nothing happens. When the value changes, it returns "mu-value-flash" for the duration of the animation, then reverts to an empty string.
It works with any data type — numbers, strings, arrays, objects. For complex values it uses deep comparison internally.
Options
const flashClass = useValueFlash(value, {
duration: 800, // Flash duration in ms (default: 600)
disabled: false, // Disable flash entirely
});Value flash automatically respects:
- •MetricProvider's animate setting — if animations are off, no flash
- •prefers-reduced-motion — respects the user's OS preference
- •First render — no flash on mount, only on subsequent changes
Combining Both
The providers nest naturally. Linked hover and value flash work together:
import {
MetricProvider,
LinkedHoverProvider,
MetricGrid,
KpiCard,
AreaChart,
BarChart,
useValueFlash,
} from "metricui";
function Dashboard({ data }) {
return (
<MetricProvider theme="indigo">
<LinkedHoverProvider>
<MetricGrid>
{/* KPIs flash when data updates */}
<LiveKpi title="Revenue" value={data.revenue} format="currency" />
<LiveKpi title="Orders" value={data.orders} format="compact" />
{/* Charts sync hover automatically */}
<AreaChart
title="Revenue Over Time"
data={data.timeSeries}
index="month"
categories={["revenue"]}
/>
<BarChart
title="Orders by Month"
data={data.timeSeries}
index="month"
categories={["orders"]}
/>
</MetricGrid>
</LinkedHoverProvider>
</MetricProvider>
);
}
function LiveKpi({ title, value, format }) {
const flashClass = useValueFlash(value);
return (
<div className={flashClass}>
<KpiCard title={title} value={value} format={format} />
</div>
);
}Linked hover is visual coordination. Value flash is a CSS animation hook. For click-based filtering, see Cross-Filtering in the Filtering guide.