System Status
Current status of all our services
Degraded Performance
All systems are running smoothly
Services
REST API
Core REST API endpoints and GraphQL services
Web Application
Main dashboard and user interface
Database Cluster
Primary PostgreSQL database with read replicas
CDN & Static Assets
Global content delivery network
Authentication Service
OAuth, SSO, and session management
Email Delivery
Transactional and notification emails
Webhook Service
Event notifications and integrations
Search Engine
Full-text search and indexing
File Storage
Object storage and file uploads
Analytics Pipeline
Data processing and reporting
Recent Incidents
Email Service Outage
majorNovember 16, 2024 at 10:15 AM PST
Email delivery has been restored. We're monitoring the service closely to ensure stability.
11:30 AM PST
We've identified a configuration issue with our email provider and are implementing a fix.
10:45 AM PST
We're investigating reports of email delivery failures. Transactional emails are currently not being sent.
10:15 AM PST
CDN Scheduled Maintenance
minorNovember 16, 2024 at 9:00 AM PST
Maintenance is progressing as planned. We expect to complete by 12:00 PM PST.
10:00 AM PST
We're performing scheduled maintenance on our CDN infrastructure. Some static assets may load slower than usual.
9:00 AM PST
Web Application Performance Degradation
minorNovember 16, 2024 at 8:30 AM PST
We're investigating reports of slower page load times in the dashboard. API services are not affected.
8:30 AM PST
Last updated: 11/17/2025, 4:45:23 PM
Subscribe to updatesInstallation
Install dependencies
npm install framer-motion lucide-reactCopy and paste the following code into your project.
"use client";
import React from "react";
import { motion } from "framer-motion";
import { CheckCircle2, AlertCircle, XCircle, Clock } from "lucide-react";
interface ServiceStatus {
id: string;
name: string;
description?: string;
status: "operational" | "degraded" | "outage" | "maintenance";
uptime?: string;
}
interface Incident {
id: string;
title: string;
status: "investigating" | "identified" | "monitoring" | "resolved";
severity: "minor" | "major" | "critical";
timestamp: string;
updates: {
message: string;
timestamp: string;
}[];
}
interface StatusPageProps {
title?: string;
description?: string;
overallStatus?: "operational" | "degraded" | "outage";
services: ServiceStatus[];
incidents?: Incident[];
uptimePercentage?: string;
className?: string;
}
export function StatusPage({
title = "System Status",
description = "Current status of all our services",
overallStatus = "operational",
services,
incidents = [],
uptimePercentage = "99.99",
className = "",
}: StatusPageProps) {
const getStatusConfig = (status: ServiceStatus["status"]) => {
switch (status) {
case "operational":
return {
label: "Operational",
color: "text-emerald-600 dark:text-emerald-400",
bg: "bg-emerald-50 dark:bg-emerald-950/30",
dot: "bg-emerald-500",
icon: CheckCircle2,
};
case "degraded":
return {
label: "Degraded Performance",
color: "text-amber-600 dark:text-amber-400",
bg: "bg-amber-50 dark:bg-amber-950/30",
dot: "bg-amber-500",
icon: AlertCircle,
};
case "outage":
return {
label: "Major Outage",
color: "text-red-600 dark:text-red-400",
bg: "bg-red-50 dark:bg-red-950/30",
dot: "bg-red-500",
icon: XCircle,
};
case "maintenance":
return {
label: "Maintenance",
color: "text-blue-600 dark:text-blue-400",
bg: "bg-blue-50 dark:bg-blue-950/30",
dot: "bg-blue-500",
icon: Clock,
};
}
};
const overallConfig = getStatusConfig(
overallStatus === "operational"
? "operational"
: overallStatus === "degraded"
? "degraded"
: "outage",
);
const OverallIcon = overallConfig.icon;
return (
<section className={`w-full py-24 ${className}`}>
<div className="mx-auto max-w-5xl px-4 sm:px-6 lg:px-8">
{/* Header */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, ease: "easeOut" }}
className="mb-12 text-center"
>
<h2 className="mb-4 text-4xl font-bold tracking-tight text-zinc-900 dark:text-white sm:text-5xl">
{title}
</h2>
<p className="mx-auto max-w-2xl text-lg text-zinc-600 dark:text-zinc-400">
{description}
</p>
</motion.div>
{/* Overall Status Banner */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.1, ease: "easeOut" }}
className={`mb-12 overflow-hidden rounded-2xl border p-8 ${overallConfig.bg} ${
overallStatus === "operational"
? "border-emerald-200 dark:border-emerald-800"
: overallStatus === "degraded"
? "border-amber-200 dark:border-amber-800"
: "border-red-200 dark:border-red-800"
}`}
>
<div className="flex flex-col items-center gap-4 sm:flex-row sm:justify-between">
<div className="flex items-center gap-4">
<div
className={`flex h-12 w-12 items-center justify-center rounded-full ${overallConfig.bg}`}
>
<OverallIcon className={`h-6 w-6 ${overallConfig.color}`} />
</div>
<div>
<h3 className={`text-2xl font-bold ${overallConfig.color}`}>
{overallConfig.label}
</h3>
<p className="text-sm text-zinc-600 dark:text-zinc-400">
All systems are running smoothly
</p>
</div>
</div>
<div className="text-center sm:text-right">
<div className="text-3xl font-bold text-zinc-900 dark:text-white">
{uptimePercentage}%
</div>
<div className="text-sm text-zinc-600 dark:text-zinc-400">
Uptime (30 days)
</div>
</div>
</div>
</motion.div>
{/* Services Status */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.2, ease: "easeOut" }}
className="mb-12"
>
<h3 className="mb-6 text-xl font-bold text-zinc-900 dark:text-white">
Services
</h3>
<div className="space-y-3">
{services.map((service, index) => {
const config = getStatusConfig(service.status);
const Icon = config.icon;
return (
<motion.div
key={service.id}
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{
duration: 0.4,
delay: 0.3 + index * 0.05,
ease: "easeOut",
}}
className="flex items-center justify-between rounded-xl border border-zinc-200 bg-white p-4 transition-all hover:shadow-md dark:border-zinc-800 dark:bg-zinc-900"
>
<div className="flex items-center gap-4">
<div
className={`flex h-10 w-10 items-center justify-center rounded-lg ${config.bg}`}
>
<Icon className={`h-5 w-5 ${config.color}`} />
</div>
<div>
<h4 className="font-semibold text-zinc-900 dark:text-white">
{service.name}
</h4>
{service.description && (
<p className="text-sm text-zinc-600 dark:text-zinc-400">
{service.description}
</p>
)}
</div>
</div>
<div className="flex items-center gap-3">
{service.uptime && (
<span className="hidden text-sm font-medium text-zinc-600 dark:text-zinc-400 sm:block">
{service.uptime}
</span>
)}
<span
className={`inline-flex items-center gap-2 rounded-full px-3 py-1 text-sm font-semibold ${config.bg} ${config.color}`}
>
<span className={`h-2 w-2 rounded-full ${config.dot}`} />
{config.label}
</span>
</div>
</motion.div>
);
})}
</div>
</motion.div>
{/* Incidents */}
{incidents.length > 0 && (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.4, ease: "easeOut" }}
>
<h3 className="mb-6 text-xl font-bold text-zinc-900 dark:text-white">
Recent Incidents
</h3>
<div className="space-y-4">
{incidents.map((incident, index) => (
<motion.div
key={incident.id}
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{
duration: 0.4,
delay: 0.5 + index * 0.05,
ease: "easeOut",
}}
className="overflow-hidden rounded-xl border border-zinc-200 bg-white dark:border-zinc-800 dark:bg-zinc-900"
>
<div className="border-b border-zinc-100 p-6 dark:border-zinc-800">
<div className="mb-2 flex items-start justify-between gap-4">
<h4 className="text-lg font-bold text-zinc-900 dark:text-white">
{incident.title}
</h4>
<span
className={`inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-semibold ${
incident.severity === "critical"
? "bg-red-50 text-red-600 dark:bg-red-950/30 dark:text-red-400"
: incident.severity === "major"
? "bg-amber-50 text-amber-600 dark:bg-amber-950/30 dark:text-amber-400"
: "bg-blue-50 text-blue-600 dark:bg-blue-950/30 dark:text-blue-400"
}`}
>
{incident.severity}
</span>
</div>
<p className="text-sm text-zinc-600 dark:text-zinc-400">
{incident.timestamp}
</p>
</div>
<div className="space-y-4 p-6">
{incident.updates.map((update, idx) => (
<div key={idx} className="flex gap-3 items-start">
<div className="">
<div className="h-2 w-2 rounded-full bg-zinc-400 dark:bg-zinc-600" />
</div>
<div className="flex-1 -mt-1.5">
<p className=" text-sm text-zinc-900 dark:text-white">
{update.message}
</p>
<p className="text-xs text-zinc-500 dark:text-zinc-500">
{update.timestamp}
</p>
</div>
</div>
))}
</div>
</motion.div>
))}
</div>
</motion.div>
)}
{/* Footer */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5, delay: 0.6, ease: "easeOut" }}
className="mt-12 text-center"
>
<p className="text-sm text-zinc-600 dark:text-zinc-400">
Last updated: {new Date().toLocaleString()}
</p>
<a
href="#"
className="mt-2 inline-flex items-center gap-2 text-sm font-semibold text-blue-600 transition-colors hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300"
>
Subscribe to updates
</a>
</motion.div>
</div>
</section>
);
}Features
- ✅ Overall status banner - Shows system-wide health at a glance
- ✅ Service monitoring - Individual status for each service
- ✅ Color-coded status - Operational, Degraded, Outage, Maintenance
- ✅ Uptime percentage - Shows 30-day uptime stats
- ✅ Incident tracking - Display recent incidents with updates
- ✅ Severity levels - Minor, Major, Critical incidents
- ✅ Clean design - Modern, professional appearance
- ✅ Responsive - Works on all screen sizes
- ✅ Dark mode ready - Beautiful in both themes
- ✅ TypeScript support - Full type safety
Usage
Basic Usage
import StatusPage from "@/components/ui/status-page";
const services = [
{
id: "api",
name: "REST API",
description: "Core REST API endpoints and GraphQL services",
status: "operational",
uptime: "100%",
},
{
id: "web-app",
name: "Web Application",
description: "Main dashboard and user interface",
status: "operational",
uptime: "99.99%",
},
{
id: "database",
name: "Database Cluster",
description: "Primary PostgreSQL database with read replicas",
status: "operational",
uptime: "99.99%",
},
];
export default function Page() {
return (
<StatusPage
overallStatus="operational"
services={services}
uptimePercentage="99.99"
/>
);
}With Incidents
const incidents = [
{
id: "inc-003",
title: "Email Service Outage",
status: "monitoring",
severity: "major",
timestamp: "November 16, 2024 at 10:15 AM PST",
updates: [
{
message:
"Email delivery has been restored. We're monitoring the service closely.",
timestamp: "11:30 AM PST",
},
{
message:
"We've identified a configuration issue and are implementing a fix.",
timestamp: "10:45 AM PST",
},
{
message: "We're investigating reports of email delivery failures.",
timestamp: "10:15 AM PST",
},
],
},
];
<StatusPage
services={services}
incidents={incidents}
overallStatus="degraded"
/>;Props
StatusPageProps
| Prop | Type | Default | Description |
|---|---|---|---|
services | ServiceStatus[] | Required | Array of services |
overallStatus | "operational" | "degraded" | "outage" | "operational" | Overall system status |
title | string | "System Status" | Section title |
description | string | "Current status of..." | Section description |
incidents | Incident[] | [] | Array of incidents |
uptimePercentage | string | "99.99" | 30-day uptime percentage |
className | string | "" | Additional CSS classes |
ServiceStatus
| Prop | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique identifier |
name | string | Yes | Service name |
description | string | No | Service description |
status | "operational" | "degraded" | "outage" | "maintenance" | Yes | Current status |
uptime | string | No | Uptime percentage |
Incident
| Prop | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique identifier |
title | string | Yes | Incident title |
status | "investigating" | "identified" | "monitoring" | "resolved" | Yes | Incident status |
severity | "minor" | "major" | "critical" | Yes | Severity level |
timestamp | string | Yes | Incident timestamp |
updates | {message: string, timestamp: string}[] | Yes | Status updates |
TypeScript Interface
interface ServiceStatus {
id: string;
name: string;
description?: string;
status: "operational" | "degraded" | "outage" | "maintenance";
uptime?: string;
}
interface Incident {
id: string;
title: string;
status: "investigating" | "identified" | "monitoring" | "resolved";
severity: "minor" | "major" | "critical";
timestamp: string;
updates: {
message: string;
timestamp: string;
}[];
}
interface StatusPageProps {
title?: string;
description?: string;
overallStatus?: "operational" | "degraded" | "outage";
services: ServiceStatus[];
incidents?: Incident[];
uptimePercentage?: string;
className?: string;
}Use Cases
Perfect for:
- Public status pages - Build trust with transparent service status
- Internal system monitoring - Track infrastructure health
- Customer transparency - Show real-time service availability
- SLA reporting - Display uptime metrics and commitments
- Incident communication - Keep users informed during outages
- Service health dashboards - Monitor multiple services at once
- Trust building - Demonstrate reliability and transparency
- Support pages - Reduce support tickets with proactive updates
Status Types
Operational
- Color: Green (Emerald)
- Icon: CheckCircle
- Use: Service is working normally
Degraded Performance
- Color: Amber
- Icon: AlertCircle
- Use: Service is slow but functional
Major Outage
- Color: Red
- Icon: XCircle
- Use: Service is down
Maintenance
- Color: Blue
- Icon: Clock
- Use: Scheduled maintenance
Customization
Change Status Colors
case "operational":
return {
label: "Operational",
color: "text-green-600 dark:text-green-400", // Your brand color
bg: "bg-green-50 dark:bg-green-950/30",
dot: "bg-green-500",
icon: CheckCircle2,
};Add Historical Uptime
// Add uptime history visualization
<div className="mt-8">
<h4 className="mb-4 font-semibold">90-Day Uptime History</h4>
<div className="flex gap-1">
{Array.from({length: 90}).map((_, i) => (
<div
key={i}
className="h-8 w-1 rounded-sm bg-emerald-500"
title="100% uptime"
/>
))}
</div>
</div>Add Subscribe Button
<button className="mt-4 rounded-lg bg-blue-600 px-6 py-2 font-semibold text-white hover:bg-blue-700">
Subscribe to Updates
</button>Real-Time Updates
"use client";
import {useEffect, useState} from "react";
export default function LiveStatusPage() {
const [services, setServices] = useState(initialServices);
useEffect(() => {
// Poll for updates every 30 seconds
const interval = setInterval(async () => {
const response = await fetch("/api/status");
const data = await response.json();
setServices(data.services);
}, 30000);
return () => clearInterval(interval);
}, []);
return <StatusPage services={services} />;
}Common Patterns
Complete Status Page
const statusData = {
overallStatus: "operational",
services: [
{
id: "api",
name: "REST API",
description: "Core REST API endpoints and GraphQL services",
status: "operational",
uptime: "100%",
},
{
id: "web",
name: "Web Application",
description: "Main dashboard and user interface",
status: "operational",
uptime: "99.99%",
},
{
id: "db",
name: "Database Cluster",
description: "Primary PostgreSQL database with read replicas",
status: "operational",
uptime: "100%",
},
{
id: "cdn",
name: "CDN & Static Assets",
description: "Global content delivery network",
status: "operational",
uptime: "99.95%",
},
],
incidents: [],
uptimePercentage: "99.99",
};
<StatusPage {...statusData} />;During an Outage
const outageData = {
overallStatus: "outage",
services: [
{
id: "api",
name: "REST API",
description: "Core REST API endpoints and GraphQL services",
status: "outage",
uptime: "98.50%",
},
{
id: "web",
name: "Web Application",
description: "Main dashboard and user interface",
status: "degraded",
uptime: "99.20%",
},
{
id: "database",
name: "Database Cluster",
description: "Primary PostgreSQL database with read replicas",
status: "operational",
uptime: "99.99%",
},
],
incidents: [
{
id: "inc-123",
title: "API Service Disruption",
status: "investigating",
severity: "critical",
timestamp: "November 16, 2024 at 10:00 AM PST",
updates: [
{
message:
"We're investigating reports of API errors affecting all endpoints.",
timestamp: "10:00 AM PST",
},
],
},
],
uptimePercentage: "98.50",
};Maintenance Mode
const maintenanceData = {
overallStatus: "degraded",
services: [
{
id: "cdn",
name: "CDN & Static Assets",
description: "Global content delivery network",
status: "maintenance",
uptime: "99.95%",
},
{
id: "api",
name: "REST API",
description: "Core REST API endpoints and GraphQL services",
status: "operational",
uptime: "100%",
},
{
id: "web",
name: "Web Application",
description: "Main dashboard and user interface",
status: "operational",
uptime: "99.99%",
},
],
incidents: [
{
id: "maint-001",
title: "CDN Scheduled Maintenance",
status: "identified",
severity: "minor",
timestamp: "November 16, 2024 at 2:00 AM PST",
updates: [
{
message:
"Maintenance is progressing as planned. Expected completion: 4:00 AM PST.",
timestamp: "3:00 AM PST",
},
{
message:
"We're performing scheduled maintenance on our CDN infrastructure. Some static assets may load slower than usual.",
timestamp: "2:00 AM PST",
},
],
},
],
uptimePercentage: "99.89",
};Integration
With Monitoring Service
// Fetch status from monitoring service
async function getServiceStatus() {
const response = await fetch("https://api.monitoring.com/status");
const data = await response.json();
return data.services.map((service) => ({
id: service.id,
name: service.name,
status: service.healthy ? "operational" : "outage",
uptime: service.uptime,
}));
}With Webhook Notifications
// Send webhook when status changes
async function notifyStatusChange(service: ServiceStatus) {
await fetch("https://hooks.slack.com/services/YOUR/WEBHOOK/URL", {
method: "POST",
body: JSON.stringify({
text: `${service.name} is now ${service.status}`,
}),
});
}