The Activity Timeline component displays a chronological list of user lifecycle events with intelligent grouping, collapsing, and load-more functionality. It prioritizes user-relevant events while reducing noise through smart grouping rules.
File Structure:
components/activity-timeline/
├── activity-timeline.tsx # Main component with grouping logic
├── activity-timeline-item.tsx # Individual event row
├── activity-timeline-empty.tsx # Empty/error/loading states
├── index.ts # Component exports
└── __tests__/
└── activity-timeline.test.tsx # Comprehensive test suite
lib/
├── activity-timeline.ts # Grouping, formatting utilities
types/
└── activity.ts # Type definitions
The main component orchestrates:
- Data grouping by activity type
- Pagination / "load more" functionality
- State management for expanded/collapsed groups
- Loading, error, and empty state handling
Key Features:
- 🎯 Smart Grouping: Events grouped by type (Predictions, Events, Disputes, etc.)
- 📊 Intelligent Collapsing: Automatically collapses noisy event groups (3+ events)
- ⏰ Relative Timestamps: Shows "2 hours ago", "Yesterday", etc.
- 📥 Load More: Pagination for browsing older activities
- ♿ Accessible: Full keyboard navigation and screen reader support
Renders individual event rows with:
- Timeline connector (colored dot + vertical line)
- Event icon and type
- Title and optional description
- Timestamp (time + relative)
- Amount for transactions
- Metadata tags
Example Event Flow:
• (dot) ─────── Title [Time]
│ Description [2 hours ago]
│ Amount: +500 USDC
├── Metadata: category:crypto
ActivityTimelineEmpty:
- Shown when zero activities exist
- Clear messaging + call-to-action
- Archive icon for visual context
ActivityTimelineError:
- Error message and icon
- Technical error details
- Retry button for recovery
ActivityTimelineLoading:
- Skeleton loaders matching component structure
- Smooth animation to indicate in-progress
- Maintains layout stability
Events are grouped into 6 categories:
| Category | Icon | Events | Color |
|---|---|---|---|
| Predictions | 🎯 | Placed, Settled | Purple |
| Events | 📅 | Created, Verified, Opened, Closed | Cyan |
| Disputes | Filed, Resolved | Red | |
| Transactions | 💳 | Deposit, Withdrawal, Claimed | Green |
| Account | 👤 | Updated, Settings Changed | Blue |
| Verification | ✅ | Requested, Approved | Amber |
Groups are automatically collapsed when:
- Contains 3 or more events (within 60-minute window)
- AND contains no "priority" events
Priority Events (Always Visible):
prediction_settled- User settlementdispute_resolved- Resolution of disputeswinnings_claimed- Financial gain
Events within each group are sorted:
- Primary: By timestamp (newest first)
- Secondary: By event priority
The main timestamp uses human-readable relative format:
Just now (< 1 minute)
5 minutes ago (1-60 minutes)
2 hours ago (1-24 hours)
Yesterday (24-48 hours)
3 days ago (2-7 days)
Mar 12, 2024 (7+ days, shows date)
Shows precise time in HH:MM AM/PM format:
2:45 PM (at top-right of event)
Full timestamp with timezone:
March 15, 2024, 2:45 PM EST
- Page Size: 6 activity groups per page
- Load Trigger: User clicks "Load Older Activities" button
- Button Position: Centered below last visible group
- Feedback: Shows remaining groups available
function handleLoadMore() {
// Load next page of activities
// Append to visible groups
// Update hasMore state
// Call onLoadMore callback
}- Single column layout
- Full-width cards
- Touch-friendly spacing (larger tap targets)
- Stacked timestamp (time above relative)
- Hidden metadata tags
- Simplified icons
- Optimal card width
- Sidebar (if needed)
- Improved spacing
- All metadata visible
- Multi-column option
- Hover effects
- Full detail display
- Optimized spacing
Group Headers:
- Background: Soft pastel (e.g.,
bg-[#F3E8FF]for purple) - Icon background: Transparent color overlay
- Border: Light gray divider
- Hover: Subtle shadow effect
Timeline Dots:
- Size: 3px mobile, 4px desktop
- Color: Group-specific color
- Border: 2px white
Timeline Line:
- Width: 0.5px
- Color: Group color with 30% opacity
- Height: 48px between events
Cards:
- Border: 1px gray-200
- Background: White
- Hover bg: Gray-50
- Border-radius: 8px
- Shadow (hover): Subtle
Group Header:
- Font: Medium semibold
- Size: 14px mobile, 16px desktop
- Color: Gray-900
Event Title:
- Font: Medium
- Size: 14px mobile, 16px desktop
- Color: Gray-900
Event Description:
- Font: Regular
- Size: 12px mobile, 14px desktop
- Color: Gray-600
Timestamps:
- Font: Regular
- Size: 12px mobile, 14px desktop
- Color: Gray-500/700
- Relative: Bold (700)
Amount:
- Font: Semibold
- Size: 14px mobile, 16px desktop
- Color: Green-600 (deposit) / Red-600 (withdrawal)
- Tab through all interactive elements
- Space/Enter to toggle group expansion
- Load More button fully keyboard accessible
- Semantic HTML structure
- Descriptive ARIA labels
- Event descriptions read out
- Group count announced
- Timestamps include full date format
- Sufficient color contrast (WCAG AA)
- Icons paired with text (not icon-only)
- Focus indicators on interactive elements
- Flexible text sizing
- Virtual scrolling for 100+ events (optional)
- Memoized group calculations
- Lazy-loaded expanded groups
- CSS containment on cards
- Component: ~8KB minified
- Utils: ~3KB minified
- Types: ~1KB minified
- Total: ~12KB
- Efficient grouping algorithms
- Pagination prevents large DOM trees
- Event delegation for click handlers
<ActivityTimeline
error="Failed to fetch activities. Please check your connection."
onRetry={handleRetry}
/>- Gracefully handles missing descriptions
- Omits optional fields (amount, metadata)
- Default icons for unknown event types
- Falls back to UTC format
- Invalid dates show as "-"
- Grouping Logic: Verify correct grouping by type
- Collapse Rules: Test collapse conditions
- Timestamp Formatting: All time formats
- Pagination: Load more behavior
- Component Rendering: All states (default, loading, error, empty)
- User Interactions: Click handlers, group toggle
- Prop Changes: Responsive to prop updates
- Screenshot comparisons for each state
- Mobile/tablet/desktop variants
- Light/dark mode support
- Full flow: Load → Toggle Group → Load More
- Error recovery
- Accessibility testing (axe, WAVE)
import { ActivityTimeline } from "@/components/activity-timeline";
export function ActivityPage() {
const activities = useActivities(); // Your hook
return (
<ActivityTimeline
activities={activities}
pageSize={6}
onLoadMore={handleLoadMore}
/>
);
}export function ActivityPage() {
const [activities, setActivities] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetchActivities()
.then(setActivities)
.catch(setError)
.finally(() => setLoading(false));
}, []);
return (
<ActivityTimeline
activities={activities}
isLoading={loading}
error={error}
onLoadMore={() => fetchMoreActivities()}
/>
);
}<div className="bg-white rounded-lg p-6">
<h2 className="text-2xl font-bold mb-6">Recent Activity</h2>
<ActivityTimeline
className="max-w-2xl"
pageSize={8}
/>
</div>- Date separators ("Today", "March 15")
- Search/filter within timeline
- Custom event type icons (from app)
- Notification badges for unread events
- Event detail drawer/modal
- Export timeline (CSV/PDF)
- Bulk actions (archive, delete)
- Timeline statistics (events over time)
- Virtual scrolling for 1000+ events
- Server-side pagination
- Optimistic updates for actions
- Caching strategy
- Track which groups users expand
- Monitor load more usage
- Detect abandoned activities
- User engagement metrics
- Chrome/Edge: ✅ Latest 2 versions
- Firefox: ✅ Latest 2 versions
- Safari: ✅ Latest 2 versions
- Mobile: ✅ iOS 14+, Android 10+
Visit /dashboard/activity-timeline-demo to see:
- Default view (grouped & collapsed)
- Expanded view (all groups open)
- Empty state
- Error handling
- Loading skeleton
- Interactive examples
Refer to:
/types/activity.ts- Type definitions/lib/activity-timeline.ts- Utility functionsactivity-timeline.test.tsx- Test examples