Bento Dashboard
Variable-span grid tiles, live HTMX metrics, SaaS dashboard patterns.
Technologies Demonstrated
Color Palette
[Alpine]Primary
#6366f1
Secondary
#8b5cf6
Accent
#10b981
Danger
#ef4444
Warning
#f59e0b
Text
#0f172a
Muted
#64748b
Click any swatch to copy hex value to clipboard.
<div class="grid grid-cols-2 sm:grid-cols-4 md:grid-cols-7 gap-4"> @bentoSwatch("Primary", "#6366f1") @bentoSwatch("Secondary", "#8b5cf6") @bentoSwatch("Accent", "#10b981") @bentoSwatch("Danger", "#ef4444") @bentoSwatch("Warning", "#f59e0b") @bentoSwatch("Text", "#0f172a") @bentoSwatch("Muted", "#64748b") </div>
Typography
Display — 2.5rem / Bold
Dashboard
Heading — 1.25rem / Medium
Active Users Over Time
DM Sans Weights
Light — secondary descriptions and metadata
Regular — body text and standard content
Medium — labels, navigation, and UI text
Bold — headings and metric values
Caption — 0.8125rem
Last updated 2 minutes ago · Auto-refreshes every 3 seconds
Spacing Scale
Base unit: 4px
Buttons
[Alpine]Variants
Sizes
Toggle [Alpine]
<div class="bento-card space-y-6"> <div> <p class="text-xs mb-3" style="color: var(--color-text-muted); text-transform: uppercase; letter-spacing: 0.08em;">Variants</p> <div class="flex flex-wrap gap-3"> <button class="bento-btn text-sm">Primary</button> <button class="bento-btn bento-btn-secondary text-sm">Secondary</button> <button class="bento-btn text-sm" disabled style="opacity: 0.4; cursor: not-allowed;">Disabled</button> </div> </div> <div> <p class="text-xs mb-3" style="color: var(--color-text-muted); text-transform: uppercase; letter-spacing: 0.08em;">Sizes</p> <div class="flex flex-wrap items-center gap-3"> <button class="bento-btn" style="font-size: 0.75rem; padding: 0.25rem 0.625rem;">Small</button> <button class="bento-btn text-sm">Medium</button> <button class="bento-btn" style="font-size: 1rem; padding: 0.75rem 1.5rem;">Large</button> </div> </div> <div> <p class="text-xs mb-3" style="color: var(--color-text-muted); text-transform: uppercase; letter-spacing: 0.08em;">Toggle [Alpine]</p> <div x-data="{ on: false }" class="flex items-center gap-4"> <button class="bento-btn text-sm" { templ.Attributes{ "@click": "on = !on", ":style": "on ? 'background: var(--color-accent)' : ''", }... } > <span x-text="on ? 'Active ✓' : 'Toggle Me'">Toggle Me</span> </button> <span class="text-xs" style="color: var(--color-text-muted);" x-text="on ? 'state: on' : 'state: off'">state: off</span> </div> </div> </div>
Live Metric Tiles
[HTMX]These tiles poll /guides/bento/metrics every 3 seconds via HTMX.
Active Users
1,247
+12% ↑
Revenue
$48.2K
+8% ↑
Error Rate
0.3%
-0.1% ↓
Response Time
142ms
+5ms →
<div class="bento-grid" hx-get="/guides/bento/metrics" hx-trigger="every 3s" hx-swap="innerHTML" > <!-- initial static tiles (replaced by HTMX on first poll) --> <div class="bento-card bento-span-6 flex flex-col gap-2"> <p class="text-xs font-medium" style="color:var(--color-text-muted)">Active Users</p> <p class="text-2xl font-bold" style="color:var(--color-text)">1,247</p> <p class="text-xs font-medium" style="color:var(--color-accent)">+12% ↑</p> </div> <div class="bento-card bento-span-6 flex flex-col gap-2"> <p class="text-xs font-medium" style="color:var(--color-text-muted)">Revenue</p> <p class="text-2xl font-bold" style="color:var(--color-text)">$48.2K</p> <p class="text-xs font-medium" style="color:var(--color-accent)">+8% ↑</p> </div> <div class="bento-card bento-span-6 flex flex-col gap-2"> <p class="text-xs font-medium" style="color:var(--color-text-muted)">Error Rate</p> <p class="text-2xl font-bold" style="color:var(--color-text)">0.3%</p> <p class="text-xs font-medium" style="color:var(--color-danger)">-0.1% ↓</p> </div> <div class="bento-card bento-span-6 flex flex-col gap-2"> <p class="text-xs font-medium" style="color:var(--color-text-muted)">Response Time</p> <p class="text-2xl font-bold" style="color:var(--color-text)">142ms</p> <p class="text-xs font-medium" style="color:var(--color-text-muted)">+5ms →</p> </div> </div>
Sortable Data Table
[Alpine]| Name | Status | Amount |
|---|---|---|
| Project Alpha | Active | $12,400 |
| Project Beta | Review | $8,200 |
| Project Gamma | Active | $31,000 |
| Project Delta | Paused | $4,100 |
| Project Epsilon | Active | $19,750 |
| Project Zeta | Review | $6,900 |
<div x-data="{ sort: 'name', dir: 'asc' }" class="bento-card overflow-x-auto"> <table class="w-full text-sm"> <thead> <tr style="border-bottom: 1px solid var(--color-border);"> <th class="text-left p-3 font-medium cursor-pointer select-none" style="color:var(--color-text-muted)" { templ.Attributes{"@click": "sort='name'; dir = dir==='asc'?'desc':'asc'"}... } > Name <span x-text="sort==='name' ? (dir==='asc' ? '↑' : '↓') : '↕'"></span> </th> <th class="text-left p-3 font-medium cursor-pointer select-none" style="color:var(--color-text-muted)" { templ.Attributes{"@click": "sort='status'; dir = dir==='asc'?'desc':'asc'"}... } > Status <span x-text="sort==='status' ? (dir==='asc' ? '↑' : '↓') : '↕'"></span> </th> <th class="text-left p-3 font-medium cursor-pointer select-none" style="color:var(--color-text-muted)" { templ.Attributes{"@click": "sort='amount'; dir = dir==='asc'?'desc':'asc'"}... } > Amount <span x-text="sort==='amount' ? (dir==='asc' ? '↑' : '↓') : '↕'"></span> </th> </tr> </thead> <tbody> for _, row := range []struct{ name, status, amount, statusColor string }{ {"Project Alpha", "Active", "$12,400", "var(--color-accent)"}, {"Project Beta", "Review", "$8,200", "var(--color-warning)"}, {"Project Gamma", "Active", "$31,000", "var(--color-accent)"}, {"Project Delta", "Paused", "$4,100", "var(--color-text-muted)"}, {"Project Epsilon", "Active", "$19,750", "var(--color-accent)"}, {"Project Zeta", "Review", "$6,900", "var(--color-warning)"}, } { <tr style="border-bottom: 1px solid var(--color-border);"> <td class="p-3 font-medium" style="color:var(--color-text)">{ row.name }</td> <td class="p-3"> <span class="px-2 py-0.5 rounded text-xs font-medium" style={ "color:" + row.statusColor + ";background:" + row.statusColor + "18" }>{ row.status }</span> </td> <td class="p-3 font-mono text-sm" style="color:var(--color-text)">{ row.amount }</td> </tr> } </tbody> </table> </div>
Status Indicators
[Alpine]Click any service to cycle status
<div x-data="{ statuses: [ { name: 'API Gateway', state: 0 }, { name: 'Database', state: 0 }, { name: 'CDN', state: 0 }, { name: 'Auth Service', state: 1 }, { name: 'Queue Worker', state: 2 } ] }" class="bento-card" > <p class="text-xs mb-4" style="color: var(--color-text-muted); text-transform: uppercase; letter-spacing: 0.08em;">Click any service to cycle status</p> <div class="flex flex-wrap gap-3"> <template x-for="svc in statuses" :key="svc.name"> <button class="flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium transition-all cursor-pointer" style="border: 1px solid var(--color-border); background: var(--color-surface);" { templ.Attributes{"@click": "svc.state = (svc.state + 1) % 3"}... } > <span class="w-2 h-2 rounded-full" { templ.Attributes{":class": "svc.state === 0 ? 'bg-emerald-500' : svc.state === 1 ? 'bg-amber-400' : 'bg-red-500'"}... } ></span> <span x-text="svc.name" style="color: var(--color-text);"></span> <span class="text-xs font-normal" { templ.Attributes{ "x-text": "svc.state === 0 ? 'Active' : svc.state === 1 ? 'Warning' : 'Down'", ":style": "svc.state === 0 ? 'color:var(--color-accent)' : svc.state === 1 ? 'color:var(--color-warning)' : 'color:var(--color-danger)'", }... } ></span> </button> </template> </div> </div>
Cards & Panels
[Alpine]Static Card
A standard dashboard tile with rounded corners, subtle shadow, and clean border. Content stays minimal.
Expandable Panel
+Revealed content with smooth transition. Alpine handles the toggle with zero server round-trips.
expanded: true
border-radius: 12px
shadow: subtle
<div class="bento-card" style="padding: 0;" x-data="{ expanded: false }"> <div class="p-5 flex items-center justify-between cursor-pointer" { templ.Attributes{"@click": "expanded = !expanded"}... } > <h3 class="text-sm font-semibold" style="color: var(--color-text);">Expandable Panel</h3> <span class="text-lg transition-transform duration-200" style="color: var(--color-text-muted);" { templ.Attributes{":class": "expanded ? 'rotate-45' : ''"}... } >+</span> </div> <div x-show="expanded" x-transition style="border-top: 1px solid var(--color-border);"> <div class="p-5"> <p class="text-sm mb-3" style="color: var(--color-text-muted);"> Revealed content with smooth transition. Alpine handles the toggle with zero server round-trips. </p> <div class="rounded-lg p-3 text-xs font-mono" style="background: var(--color-surface-2); color: var(--color-text-muted);"> <p>expanded: true</p> <p>border-radius: 12px</p> <p>shadow: subtle</p> </div> </div> </div> </div>
Forms
[HTMX]<form hx-post="/guides/bento/demo-form" hx-target="#bento-form-response" hx-swap="innerHTML" class="space-y-4" > <div class="grid grid-cols-1 sm:grid-cols-2 gap-4"> <div> <label class="block text-xs font-medium mb-1.5" style="color: var(--color-text-muted);" for="bento-name">Name</label> <input id="bento-name" name="name" type="text" placeholder="Jane Smith" class="bento-input"/> </div> <div> <label class="block text-xs font-medium mb-1.5" style="color: var(--color-text-muted);" for="bento-email">Email</label> <input id="bento-email" name="email" type="email" placeholder="jane@company.com" class="bento-input"/> </div> </div> <div> <label class="block text-xs font-medium mb-1.5" style="color: var(--color-text-muted);" for="bento-plan">Plan</label> <select id="bento-plan" name="plan" class="bento-input cursor-pointer"> <option value="">— Select plan —</option> <option value="starter">Starter</option> <option value="pro">Pro</option> <option value="enterprise">Enterprise</option> </select> </div> <div class="flex items-center gap-3"> <input type="checkbox" id="bento-analytics" name="analytics" class="w-4 h-4 cursor-pointer" style="accent-color: var(--color-primary);"/> <label for="bento-analytics" class="text-sm cursor-pointer" style="color: var(--color-text);">Enable analytics dashboard</label> </div> <!-- Radio buttons --> <div> <p class="text-xs font-medium mb-2" style="color: var(--color-text-muted);">Billing Cycle</p> <div class="space-y-2"> <label class="flex items-center gap-3 cursor-pointer text-sm" style="color: var(--color-text);"> <input type="radio" name="billing" value="monthly" class="w-4 h-4 cursor-pointer" style="accent-color: var(--color-primary);"/> Monthly </label> <label class="flex items-center gap-3 cursor-pointer text-sm" style="color: var(--color-text);"> <input type="radio" name="billing" value="annual" checked class="w-4 h-4 cursor-pointer" style="accent-color: var(--color-primary);"/> Annual (save 20%) </label> </div> </div> <button type="submit" class="bento-btn text-sm">Submit via HTMX</button> </form>
Alerts & Notices
Success
Operation completed successfully.
Warning
Resource usage approaching limits.
Error
Failed to connect to database.