Next.js 14 + Tailwind CSS: Building a Dark-Theme Financial Dashboard
Next.js 14 + Tailwind CSS: Building a Dark-Theme Financial Dashboard
Here's how we built ClawDUX's dashboard — a production financial UI that handles real-time data, complex layouts, and looks good doing it.
Project Setup
npx create-next-app@14 dashboard --typescript --tailwind --app
The Design System
Every financial UI needs three things: data density, visual hierarchy, and color that communicates.
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
surface: {
DEFAULT: '#0f1117',
card: '#1a1d27',
elevated: '#232733',
border: '#2a2e3a',
},
primary: {
50: '#eff6ff',
400: '#60a5fa',
500: '#3b82f6',
600: '#2563eb',
},
profit: '#22c55e',
loss: '#ef4444',
},
fontFamily: {
mono: ['SF Mono', 'Fira Code', 'monospace'],
},
},
},
};
Component: Data Table
Financial data needs monospace numbers for alignment:
interface Column<T> {
key: keyof T;
label: string;
align?: 'left' | 'right';
render?: (value: any, row: T) => React.ReactNode;
}
function DataTable<T extends Record<string, any>>({
data,
columns,
}: {
data: T[];
columns: Column<T>[];
}) {
return (
<div className="bg-surface-card border border-surface-border
rounded-2xl overflow-hidden">
<table className="w-full">
<thead>
<tr className="border-b border-surface-border">
{columns.map((col) => (
<th
key={String(col.key)}
className={`px-4 py-3 text-xs font-semibold
text-gray-500 uppercase tracking-wider
text-${col.align || 'left'}`}
>
{col.label}
</th>
))}
</tr>
</thead>
<tbody className="divide-y divide-surface-border">
{data.map((row, i) => (
<tr
key={i}
className="hover:bg-surface-elevated/50
transition-colors"
>
{columns.map((col) => (
<td
key={String(col.key)}
className={`px-4 py-3 text-sm font-mono
text-${col.align || 'left'}`}
>
{col.render
? col.render(row[col.key], row)
: row[col.key]}
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
);
}
// Usage
<DataTable
data={strategies}
columns={[
{ key: 'title', label: 'Strategy', align: 'left' },
{ key: 'returnPct', label: 'Return', align: 'right',
render: (v) => (
<span className={v > 0 ? 'text-profit' : 'text-loss'}>
{v > 0 ? '+' : ''}{v.toFixed(1)}%
</span>
)
},
{ key: 'sharpeRatio', label: 'Sharpe', align: 'right',
render: (v) => v.toFixed(2)
},
{ key: 'price', label: 'Price', align: 'right',
render: (v) => `$${(Number(v) / 1e6).toFixed(2)}`
},
]}
/>
Performance: ISR for Dashboard
// app/dashboard/page.tsx
export const revalidate = 60; // Revalidate every 60 seconds
export default async function DashboardPage() {
const data = await fetchDashboardData();
return (
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4 p-6">
<StatCard title="Total Volume" value={data.volume} />
<StatCard title="Active Strategies" value={data.strategies} />
<StatCard title="Avg Sharpe" value={data.avgSharpe} />
<div className="lg:col-span-2">
<DataTable data={data.topStrategies} columns={...} />
</div>
<div>
<RecentActivity activities={data.recent} />
</div>
</div>
);
}
This entire architecture is running in production on ClawDUX, serving real-time strategy data to traders and AI agents.
The core logic discussed in this article has been integrated into the ClawDUX API. Access ClawDUX-core for full permissions, or browse the marketplace to discover verified trading strategies.