Cell Diff Flashing
Highlight frequent data updates by momentarily flashing modified cells. This visual cue helps users track real-time changes in high-frequency data streams.
Note
Implement cell flashing using a custom renderer that triggers a CSS animation when the cell value updates. This guide covers several approaches for cell flashing. Review the Cell Renderers guide before you start.
Flashing Cells On Change
To flash a cell when its value changes, compare the current and previous values. If the values differ, apply a CSS flash animation. Click Update Data to randomly change cell values.
The cell flashing logic lives in the NumberCell component. NumberCell is a custom cell renderer that the grid
columns use. The component tracks the previous value and applies the "flash" animation
in an effect whenever the value changes.
export function NumberCell({ api, column, row }: Grid.T.CellRendererParams<GridSpec>) { const field = api.columnField(column, row) as number;
const prevRef = useRef(field); const prev = prevRef.current;
const value = typeof field === "number" ? formatter.format(field) : "-";
const diff = field - (prev ?? field); if (prev !== field) prevRef.current = field;
const ref = useRef<HTMLDivElement>(null); useEffect(() => { if (!ref.current) return;
ref.current.style.animation = "none"; requestAnimationFrame(() => { ref.current!.style.animation = "flash 1s ease-out forwards"; }); }, [diff]);
return ( <div ref={ref} className="flex h-full items-center justify-end gap-2 tabular-nums tracking-tighter"> {value} </div> );}Enhanced Flash
Flashing the cell background indicates a value changed but doesn’t show the change’s direction or magnitude. To provide context, flash the value itself, as shown in the demo below.
This demo reuses the change-detection logic from the previous example but alters the rendering. Instead of flashing the background, the cell renderer highlights the value change and then fades out the effect. See the code below.
export function NumberCell({ api, column, row }: Grid.T.CellRendererParams<GridSpec>) {20 collapsed lines
const field = api.columnField(column, row) as number;
const prevRef = useRef(field); const prev = prevRef.current;
const value = typeof field === "number" ? formatter.format(field) : "-";
const diff = field - (prev ?? field);
if (prev !== field) prevRef.current = field; const ref = useRef<HTMLDivElement>(null); useEffect(() => { if (!ref.current) return;
ref.current.style.animation = "none"; requestAnimationFrame(() => { ref.current!.style.animation = "fadeOut 3s ease-out forwards"; }); }, [diff]);
return ( <div className="flex h-full items-center justify-end gap-2 tabular-nums tracking-tighter"> {diff !== 0 && ( <div ref={ref} className={clsx( "flex items-center rounded px-1 text-[10px]", diff < 0 && "bg-red-800/20 text-red-500", diff > 0 && "bg-green-500/20 text-green-500", )} > {diff < 0 && <ArrowDownIcon width={12} height={12} />} {diff > 0 && <ArrowUpIcon width={12} height={12} />} <span>{diff.toFixed(2)}</span> </div> )}
{value} </div> );}Next Steps
- Cell Renderers: Render custom cell content with React components.
- Cell Range Selection: Learn how to select single or multiple cell ranges.
- Cell Tooltips & Popovers: Render custom tooltips or popovers on hover or click.
