Activity Feed

A clean, minimal activity feed with date grouping and user avatars. Inspired by Linear and Vercel.

Preview

Features

  • Clean list layout with subtle separators
  • Automatic date grouping (Today, Yesterday, dates)
  • User avatars with initials fallback
  • 8 activity types with semantic verbs
  • Relative timestamps (2h ago) for recent activity
  • Optional click handler for activity items
  • Loading skeleton state
  • Empty state message
  • Mobile-friendly layout with stacked text and inline timestamps

Install Summary

This kit will add the following files and dependencies to your project. Download the bundle and extract it into your project root.

Component Files

FilePath
activity-feed.tsxcomponents/data/activity-feed/activity-feed.tsx
activity-group.tsxcomponents/data/activity-feed/activity-group.tsx
activity-item.tsxcomponents/data/activity-feed/activity-item.tsx
types.tscomponents/data/activity-feed/types.ts
index.tscomponents/data/activity-feed/index.ts

Utility Files

FilePath
format.tslib/format.ts
design-tokens.tslib/design-tokens.ts

Installation

Download the complete bundle as a ZIP file, or copy the text bundle to your clipboard:

Component Files

The component consists of the following files:

1. activity-feed.tsx

activity-feed.tsx
tsx
"use client";

import { useMemo } from "react";
import { Skeleton } from "@/components/ui/skeleton";
import { ActivityGroup } from "./activity-group";

2. activity-group.tsx

activity-group.tsx
tsx
"use client";

import type { ReactNode } from "react";

interface ActivityGroupProps {

3. activity-item.tsx

activity-item.tsx
tsx
"use client";

import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { formatRelativeTime } from "@/lib/format";
import { getInitials } from "@/lib/avatar";

4. types.ts

types.ts
tsx
export type ActivityType =
  | "created"
  | "updated"
  | "deleted"
  | "commented"

5. index.ts

index.ts
tsx
export { ActivityFeed } from "./activity-feed";
export { ActivityItem } from "./activity-item";
export { ActivityGroup } from "./activity-group";
export type {
  Activity,
  ActivityActor,
  ActivityFeedProps,
  ActivityType,
} from "./types";

Shared Utilities

This component uses shared utility functions. These are included in the bundle above:

format.ts

format.ts
tsx
export function formatDate(date: Date): string {
  return date.toLocaleDateString("en-US", {
    month: "short",
    day: "numeric",
    year: "numeric",
  });
}

export function formatRelativeTime(date: Date, now: Date = new Date()): string {
  const diff = now.getTime() - date.getTime();
  const minutes = Math.floor(diff / 60000);

  if (minutes < 1) return "Just now";
  if (minutes < 60) return `${minutes}m ago`;

  const hours = Math.floor(minutes / 60);
  if (hours < 24) return `${hours}h ago`;

  const days = Math.floor(hours / 24);
  if (days < 7) return `${days}d ago`;

  return formatDate(date);
}

export function formatPrice(amount: number, currency = "USD"): string {
  return new Intl.NumberFormat("en-US", {
    style: "currency",
    currency,
    minimumFractionDigits: 0,
    maximumFractionDigits: 2,
  }).format(amount);
}

export function formatNumber(num: number): string {
  if (num >= 1_000_000) return `${(num / 1_000_000).toFixed(1)}M`;
  if (num >= 1_000) return `${(num / 1_000).toFixed(1)}K`;
  return num.toString();
}

design-tokens.ts

design-tokens.ts
tsx
// Border radius
export const radius = {
  card: "rounded-xl",
  badge: "rounded-full",
  button: "rounded-lg",

Usage

app/dashboard.tsx
tsx
import { ActivityFeed } from "@/components/data/activity-feed";
import type { Activity } from "@/components/data/activity-feed";

const activities: Activity[] = [
  {

Props

PropTypeDefault
activitiesActivity[]required
onActivityClick(activity: Activity) => void-
emptyMessagestring"No activity yet"
loadingbooleanfalse

Activity Types

TypeVerbExample
createdcreatedJohn created Project Alpha
updatedupdatedAlice updated billing settings
deleteddeletedBob deleted old project
commentedcommented onCarol commented on Issue #42
invitedinvitedJohn invited user@email.com
joinedjoinedNew user joined the team
deployeddeployedBob deployed v2.1.0
publishedpublishedAlice published blog post