Skip to content
Template Empire
Browse components

Live Update Table

A free live updating table React and Next.js component with FLIP reordering, highlighted changes and reduced motion.

Pause updates

Service latency, updating live
ServiceRegionLatency (ms)Requests/min
search-indexeu-west1452,670
billingeu-west121980
api-gatewayus-east824,210
auth-serviceus-east643,110
notificationsap-south581,590
media-cdnap-south396,720

Customise

0.8s
320
0.2
20px

Code

const columns = [
  { key: "service", label: "Service" },
  { key: "latency", label: "Latency (ms)", align: "right" },
];

const rows = [
  {
    id: "svc-search",
    status: "Spike detected",
    cells: { service: "search-index", latency: 268 },
  },
  // Add more stable-ID rows.
];

const [highlightedIds, setHighlightedIds] = useState(["svc-search"]);
const [paused, setPaused] = useState(false);

<TableLiveUpdate
  columns={columns}
  rows={rows}
  highlightedIds={highlightedIds}
  paused={paused}
  onPausedChange={setPaused}
  caption="Service latency, updating live"
/>

Live Update Table is a free live updating table component for React and Next.js, styled with Tailwind and animated with Motion. Stable row ids drive a FLIP spring so rows glide to a new order the instant the controlled rows array changes, while rows named in highlightedIds flash once and show a static marker so a change is never colour only.

The component never streams data itself: there is no interval, simulated connection, or per-frame state inside it, so every row and every highlight is a direct, synchronous result of the props it was given. A polite live region announces one aggregate sentence, such as "2 rows updated", only when the set of changed rows actually changes, never on mount and never once per cell. An optional Pause/Resume button changes only a controlled paused flag and never buffers or discards incoming rows; with reduced motion enabled, reordering is instant and the static marker still appears exactly as it does with motion on.

Install

Add the @te registry to your components.json once:

{
  "registries": {
    "@te": "https://templateempire.io/r/{name}.json"
  }
}

Then install the component:

npx shadcn@latest add @te/table-live-update

Usage

"use client";

import { useState } from "react";
import { TableLiveUpdate } from "@/components/table-live-update";

const columns = [
  { key: "service", label: "Service" },
  { key: "latency", label: "Latency (ms)", align: "right" },
] as const;

const rows = [
  {
    id: "svc-search",
    status: "Spike detected",
    cells: { service: "search-index", latency: 268 },
  },
  {
    id: "svc-billing",
    cells: { service: "billing", latency: 121 },
  },
];

export default function Page() {
  const [paused, setPaused] = useState(false);

  return (
    <TableLiveUpdate
      columns={columns}
      rows={rows}
      highlightedIds={["svc-search"]}
      paused={paused}
      onPausedChange={setPaused}
      caption="Service latency, updating live"
    />
  );
}

Props

PropTypeDefaultDescription
columns{ key: string; label: string; align?: "left" | "right" }[]requiredTwo to six semantic columns with unique keys, in display order.
rows{ id: string; cells: Record<string, string | number>; status?: string }[]requiredControlled row dataset, one to twenty rows with unique ids, rendered in exactly the supplied order.
highlightedIdsstring[][]Ids of rows changed by the latest external update. Unknown ids are ignored rather than thrown on.
pausedbooleanfalseControlled visual stream state. Purely cosmetic on this component's side; it never buffers or discards rows.
onPausedChange(paused: boolean) => voidundefinedCalled after a Pause/Resume press. Supplying this renders the button.
captionstringrequiredRendered as a visible caption at the top of the table and as the scroll region's accessible name.
flashDurationnumber0.8Changed-row emphasis duration in seconds, clamped to 0.2 through 2.
springStiffnessnumber320Row reordering spring stiffness, clamped to 120 through 520.
density"comfortable" | "compact""comfortable"Cell spacing density.
highlightStrengthnumber0.2Changed-row accent opacity at the start of its flash, clamped to 0.2 through 1. The default is conservative because the marker's brand-coloured text is only contrast-checked against neutral panels, not against its own flash fill.
radiusnumber20Table shell radius in CSS pixels, clamped to 0 through 40.
classNamestringundefinedAdditional classes merged onto the section.

Customisation

Live Update Table exposes four Tier 3 CSS variables: live-table-accent for the flash overlay's fill, live-table-accent-text for the changed-row marker and pause button's text and icon colour, live-table-panel for the table surface, and live-table-divider for row and header borders. The fill and text accents are separate variables rather than one shared knob, so a real install always resolves marker text through the AA-safe --primary-accent rung rather than through --primary, which is tuned as a fill colour and falls short of 4.5:1 as text once panels nest. Each defaults to the shared semantic tokens, so retheme it from any ancestor without touching the component:

:root {
  --live-table-accent: var(--ring);
  --live-table-accent-text: var(--primary-accent);
  --live-table-panel: var(--card, var(--surface));
  --live-table-divider: var(--border);
}

<TableLiveUpdate
  columns={columns}
  rows={rows}
  highlightedIds={highlightedIds}
  caption="Service latency, updating live"
  density="compact"
  radius={12}
/>

Frequently asked questions

Is Live Update Table free for commercial use?
Yes. Live Update Table is MIT licensed, so you can use it in personal and commercial projects without attribution.
Does a live updating table stay accessible while it changes?
Yes. Changed rows carry a static text marker, not just a colour flash, and a polite, atomic live region announces one aggregate sentence, such as "2 rows updated", only when the set of changed rows actually changes, never on mount and never once per cell. The optional Pause/Resume button carries an accurate aria-pressed state and visible focus, and reordering uses table markup throughout (table, caption, thead, tbody, th scope="col") so assistive technology always reads the same order sighted users see. With reduced motion enabled, rows reorder instantly and the marker still appears with no animation to catch a screen reader user mid-read.
Can I control the flash and reorder motion?
Yes. flashDuration and highlightStrength tune how long and how strongly a changed row's background flashes, springStiffness tunes the spring that carries rows to their new order, and density and radius adjust cell spacing and the shell's corner radius. The component never streams data itself: pass in rows, highlightedIds and paused from your own poll, socket, or interval, and it renders exactly what it is given.

Related components

Want the full page this belongs to?Template Empire builds complete Next.js templates with this motion system throughout. Browse the paid templates that pair with these free components.Explore Template Empire templates