Skip to content

ActivityCard

The ActivityCard component displays a timeline of recent activities (e.g. changes on a PO, SO, or GR document). Each entry shows an avatar, user name, description, and timestamp. A limited number of activities are shown in the card; additional activities are available via a clickable overflow that opens a dialog with a scrollable full list.

Import

tsx
import {
  ActivityCard,
  type ActivityCardItem,
  type ActivityCardBaseItem,
  type ActivityCardProps,
} from "@tailor-platform/app-shell";

Use ActivityCardItem for each item in the standalone API. Use ActivityCardBaseItem as the minimum constraint when extending items for the compound API.

Basic Usage

tsx
const items = [
  {
    id: "1",
    actor: { name: "Hanna", avatarUrl: "/avatars/hanna.jpg" }, // avatarUrl is optional
    description: "changed the status from DRAFT to CONFIRMED",
    timestamp: new Date("2025-03-21T09:00:00"),
  },
  {
    id: "2",
    actor: { name: "Pradeep Kumar" },
    description: "created this PO",
    timestamp: new Date("2025-03-21T15:16:00"),
  },
  {
    id: "3",
    // no actor — system event with no specific subject
    description: "Status automatically changed to EXPIRED",
    timestamp: new Date("2025-03-20T10:00:00"),
  },
];

export function DocumentUpdates() {
  return <ActivityCard items={items} title="Updates" />;
}

Overflow and dialog

By default the card shows the 6 most recent activities. If there are more, a button appears at the bottom (e.g. "2 more activities"). Clicking it opens a modal dialog titled "All activities" with the full list in a scrollable area. The overflow label can be switched to a count style ("+2") via the overflowLabel prop.

tsx
<ActivityCard items={manyItems} title="Updates" maxVisible={6} overflowLabel="more" />
// or overflowLabel="count" for "+N"

Grouping by day

Set groupBy="day" to group activities under labels like "TODAY", "YESTERDAY", or a formatted date.

tsx
<ActivityCard items={items} title="Updates" groupBy="day" />

Props

PropTypeDefaultDescription
itemsActivityCardItem[]requiredList of items (newest first).
titlestring-Card title, e.g. "Updates".
maxVisiblenumber6Max activities shown in the card before overflow.
overflowLabel"more" | "count""more""N more activities" vs "+N".
groupBy"none" | "day""none"Optional grouping by day.
classNamestring-Applied to the card root.

Each activity must include: id, description, timestamp (Date or string). Optional: actor ({ name, avatarUrl? }) — omit for system events with no specific actor (initials fallback when avatarUrl is absent).


Compound API

Use the compound API when you need fully custom item rendering — custom icons, links, badges, or mixed item kinds. Items still must satisfy ActivityCardBaseItem (id + timestamp). You extend ActivityCardBaseItem with any additional fields you need.

Import

tsx
import { ActivityCard, type ActivityCardBaseItem } from "@tailor-platform/app-shell";

Parts

PartDescription
ActivityCard.RootOuter card container. Accepts the same items, title, maxVisible, overflowLabel, groupBy props as the standalone API, plus children.
ActivityCard.ItemsIterates over items and renders each via a render-prop children function. Generic over your item type.
ActivityCard.ItemA single row in the timeline. Accepts an optional indicator (any ReactNode) for the left column.

ActivityCard.Root Props

PropTypeDefaultDescription
itemsT[]requiredList of items (newest first). T must extend ActivityCardBaseItem.
titlestring-Card title, e.g. "Updates".
maxVisiblenumber6Max items shown in the card before overflow.
overflowLabel"more" | "count""more""N more activities" vs "+N".
groupBy"none" | "day""none"Optional grouping by day.
classNamestring-Applied to the card root.
childrenReact.ReactNoderequiredMust contain ActivityCard.Items.

ActivityCard.Item Props

PropTypeDefaultDescription
indicatorReact.ReactNode-Element rendered in the left column (e.g. Avatar, icon). Omit for a default timeline node.
childrenReact.ReactNode-Content for the item row (text, badges, links, etc.).
classNamestring-Additional CSS classes.

Example

tsx
import { ActivityCard, type ActivityCardBaseItem } from "@tailor-platform/app-shell";

interface MyItem extends ActivityCardBaseItem {
  kind: "approval" | "update";
  label?: string;
  message?: string;
}

const items: MyItem[] = [
  { id: "1", timestamp: new Date(), kind: "approval", label: "PO approved" },
  { id: "2", timestamp: new Date(), kind: "update", message: "Status changed to CONFIRMED" },
];

<ActivityCard.Root items={items} title="Updates" groupBy="day">
  <ActivityCard.Items<MyItem>>
    {(item) =>
      item.kind === "approval" ? (
        <ActivityCard.Item indicator={<ApprovedIcon />}>
          <p>{item.label}</p>
        </ActivityCard.Item>
      ) : (
        <ActivityCard.Item>
          <p>{item.message}</p>
        </ActivityCard.Item>
      )
    }
  </ActivityCard.Items>
</ActivityCard.Root>;

See also

  • Avatar — underlying avatar primitive used for profile images and initials