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
| File | Path |
|---|---|
| activity-feed.tsx | components/data/activity-feed/activity-feed.tsx |
| activity-group.tsx | components/data/activity-feed/activity-group.tsx |
| activity-item.tsx | components/data/activity-feed/activity-item.tsx |
| types.ts | components/data/activity-feed/types.ts |
| index.ts | components/data/activity-feed/index.ts |
Utility Files
| File | Path |
|---|---|
| format.ts | lib/format.ts |
| design-tokens.ts | lib/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
| Prop | Type | Default |
|---|---|---|
| activities | Activity[] | required |
| onActivityClick | (activity: Activity) => void | - |
| emptyMessage | string | "No activity yet" |
| loading | boolean | false |
Activity Types
| Type | Verb | Example |
|---|---|---|
| created | created | John created Project Alpha |
| updated | updated | Alice updated billing settings |
| deleted | deleted | Bob deleted old project |
| commented | commented on | Carol commented on Issue #42 |
| invited | invited | John invited user@email.com |
| joined | joined | New user joined the team |
| deployed | deployed | Bob deployed v2.1.0 |
| published | published | Alice published blog post |