gentelella
Version:
Gentelella v4 — free admin template. 60 pages, 20 chart variants, fully interactive inbox & kanban, live theme generator, component playground, PWA-ready. Vite 8, vanilla JS, no Bootstrap, no jQuery.
828 lines (717 loc) • 55.5 kB
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Playground | Gentelella 2026 v4</title>
<link rel="icon" href="../images/favicon.svg" type="image/svg+xml">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<link rel="manifest" href="/site.webmanifest">
<meta name="theme-color" content="#1ABB9C" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#1a2332" media="(prefers-color-scheme: dark)">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<link rel="apple-touch-icon" href="/images/apple-touch-icon.svg">
<meta name="description" content="Playground — UI > Playground. Free admin template by Colorlib. 60 pages, 20 chart variants, dark mode, PWA-ready.">
<meta property="og:type" content="website">
<meta property="og:title" content="Playground">
<meta property="og:description" content="Playground — UI > Playground. Free admin template by Colorlib. 60 pages, 20 chart variants, dark mode, PWA-ready.">
<meta property="og:image" content="/images/android-chrome-512x512.svg">
<meta property="og:site_name" content="Gentelella v4">
<meta name="twitter:card" content="summary_large_image">
<script>(function(){try{var t=localStorage.getItem('theme');var d=window.matchMedia('(prefers-color-scheme: dark)').matches;var theme=t||(d?'dark':'light');document.documentElement.setAttribute('data-theme',theme);}catch(e){}})();</script>
<script type="module" crossorigin src="/js/playground-C86OsVu4.js"></script>
<link rel="modulepreload" crossorigin href="/js/rolldown-runtime-DEgBLETi.js">
<link rel="modulepreload" crossorigin href="/js/toast-DgCSlJPv.js">
<link rel="modulepreload" crossorigin href="/js/menus-BVcs0GJR.js">
<link rel="modulepreload" crossorigin href="/js/modal-MTuCfURV.js">
<link rel="modulepreload" crossorigin href="/js/main-v4-BFwmMcfm.js">
<link rel="stylesheet" crossorigin href="/assets/main-v4-DDS6x4g-.css">
</head>
<body data-shell="admin" data-page="playground" data-breadcrumb="Home > UI > Playground">
<a class="skip-link" href="#main-content">Skip to main content</a>
<aside class="sidebar" aria-label="Primary navigation">
<div class="sidebar-brand">
<div class="brand-icon">G</div>
<div class="brand-name">Gentelella <small>v4</small></div>
</div>
<nav class="sidebar-nav">
<div class="nav-group">
<div class="nav-label">General</div>
<div class="nav-tree">
<button type="button" class="nav-link nav-toggle" aria-expanded="false">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="4" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="10" width="7" height="11" rx="1.5"/></svg>
<span class="nav-text">Dashboards</span>
<svg class="nav-chev" width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path d="M6 4l4 4-4 4"/></svg>
</button>
<div class="nav-sub"><div class="nav-sub-inner"><a class="nav-sublink" href="index.html">Operations</a><a class="nav-sublink" href="index2.html">Analytics</a><a class="nav-sublink" href="index3.html">Sales</a><a class="nav-sublink" href="index4.html">System health</a></div></div>
</div>
<div class="nav-tree">
<button type="button" class="nav-link nav-toggle" aria-expanded="false">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="4" y="4" width="16" height="16" rx="2"/><path d="M9 9h6M9 13h4"/></svg>
<span class="nav-text">Forms</span>
<span class="badge badge-red">Hot</span>
<svg class="nav-chev" width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path d="M6 4l4 4-4 4"/></svg>
</button>
<div class="nav-sub"><div class="nav-sub-inner"><a class="nav-sublink" href="form.html">General</a><a class="nav-sublink" href="form_advanced.html">Advanced controls</a><a class="nav-sublink" href="form_buttons.html">Buttons</a><a class="nav-sublink" href="form_upload.html">Upload</a><a class="nav-sublink" href="form_validation.html">Validation</a><a class="nav-sublink" href="form_wizards.html">Wizard</a></div></div>
</div>
<div class="nav-tree">
<button type="button" class="nav-link nav-toggle" aria-expanded="false">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 10h18M9 10v9M15 10v9"/></svg>
<span class="nav-text">Tables</span>
<svg class="nav-chev" width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path d="M6 4l4 4-4 4"/></svg>
</button>
<div class="nav-sub"><div class="nav-sub-inner"><a class="nav-sublink" href="tables.html">Static</a><a class="nav-sublink" href="tables_dynamic.html">Dynamic</a></div></div>
</div>
<div class="nav-tree">
<button type="button" class="nav-link nav-toggle" aria-expanded="false">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M4 19V5M8 19v-8M12 19V9M16 19v-5M20 19v-9"/></svg>
<span class="nav-text">Charts</span>
<span class="badge badge-teal">New</span>
<svg class="nav-chev" width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path d="M6 4l4 4-4 4"/></svg>
</button>
<div class="nav-sub"><div class="nav-sub-inner"><a class="nav-sublink" href="chartjs.html">Chart cards</a><a class="nav-sublink" href="echarts.html">ECharts gallery</a><a class="nav-sublink" href="other_charts.html">SVG charts</a></div></div>
</div>
<a class="nav-link" href="calendar.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 10h18M8 4v6M16 4v6"/></svg>
<span class="nav-text">Calendar</span>
</a>
<a class="nav-link" href="map.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><polygon points="1 6 1 22 8 18 16 22 23 18 23 2 16 6 8 2 1 6"/><line x1="8" y1="2" x2="8" y2="18"/><line x1="16" y1="6" x2="16" y2="22"/></svg>
<span class="nav-text">Map</span>
</a>
</div>
<div class="nav-group">
<div class="nav-label">Apps</div>
<a class="nav-link" href="chat.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M21 11.5a8.38 8.38 0 01-.9 3.8 8.5 8.5 0 01-7.6 4.7 8.38 8.38 0 01-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 01-.9-3.8 8.5 8.5 0 014.7-7.6 8.38 8.38 0 013.8-.9h.5a8.48 8.48 0 018 8v.5z"/></svg>
<span class="nav-text">Chat</span>
<span class="badge badge-teal">3</span>
</a>
<a class="nav-link" href="inbox.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="2" y="4" width="20" height="16" rx="3"/><path d="M2 7l10 6 10-6"/></svg>
<span class="nav-text">Inbox</span>
</a>
<a class="nav-link" href="kanban.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="6" height="14" rx="1.5"/><rect x="11" y="3" width="6" height="9" rx="1.5"/><rect x="19" y="3" width="2" height="6" rx="0.5"/></svg>
<span class="nav-text">Kanban</span>
</a>
<a class="nav-link" href="file_manager.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M3 7a2 2 0 012-2h4l2 2h7a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V7z"/></svg>
<span class="nav-text">Files</span>
</a>
<a class="nav-link" href="notifications.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M12 3a6 6 0 00-6 6c0 6-3 7-3 7h18s-3-1-3-7a6 6 0 00-6-6z"/><path d="M10.5 21a1.5 1.5 0 003 0"/></svg>
<span class="nav-text">Notifications</span>
</a>
</div>
<div class="nav-group">
<div class="nav-label">E-commerce</div>
<a class="nav-link" href="e_commerce.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M3 9l1-5h16l1 5M3 9v10a2 2 0 002 2h14a2 2 0 002-2V9M3 9h18"/><path d="M9 13a3 3 0 006 0"/></svg>
<span class="nav-text">Storefront</span>
</a>
<a class="nav-link" href="product_detail.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M20 13l-7 7a2 2 0 01-2.83 0L3 12.83V4h8.83L20 12.17a2 2 0 010 2.83z"/><circle cx="7.5" cy="7.5" r="1.5"/></svg>
<span class="nav-text">Product</span>
</a>
<div class="nav-tree">
<button type="button" class="nav-link nav-toggle" aria-expanded="false">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="9" cy="21" r="1.5"/><circle cx="20" cy="21" r="1.5"/><path d="M1 1h4l2.7 13.4a2 2 0 002 1.6h9.7a2 2 0 002-1.6L23 6H6"/></svg>
<span class="nav-text">Orders</span>
<svg class="nav-chev" width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path d="M6 4l4 4-4 4"/></svg>
</button>
<div class="nav-sub"><div class="nav-sub-inner"><a class="nav-sublink" href="orders.html">All orders</a><a class="nav-sublink" href="order_detail.html">Order detail</a></div></div>
</div>
<a class="nav-link" href="invoice.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M5 21V3h14v18l-3-2-3 2-3-2-3 2-2-2z"/><path d="M9 8h6M9 12h6M9 16h4"/></svg>
<span class="nav-text">Invoice</span>
</a>
<a class="nav-link" href="pricing_tables.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><line x1="12" y1="2" x2="12" y2="22"/><path d="M16 6H9.5a3.5 3.5 0 100 7h5a3.5 3.5 0 010 7H7"/></svg>
<span class="nav-text">Pricing</span>
</a>
</div>
<div class="nav-group">
<div class="nav-label">Projects</div>
<a class="nav-link" href="projects.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/></svg>
<span class="nav-text">All projects</span>
</a>
<a class="nav-link" href="project_detail.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="2" y="3" width="20" height="18" rx="2"/><path d="M2 8h20"/></svg>
<span class="nav-text">Project detail</span>
</a>
</div>
<div class="nav-group">
<div class="nav-label">UI library</div>
<a class="nav-link" href="general_elements.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M4 6h16M4 12h16M4 18h10"/></svg>
<span class="nav-text">Elements</span>
</a>
<a class="nav-link" href="widgets.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="2" y="3" width="20" height="18" rx="2"/><path d="M2 8h20"/></svg>
<span class="nav-text">Widgets</span>
<span class="badge badge-blue">5</span>
</a>
<a class="nav-link active" href="playground.html" aria-current="page">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M16 18l6-6-6-6M8 6l-6 6 6 6"/></svg>
<span class="nav-text">Playground</span>
<span class="badge badge-teal">New</span>
</a>
<a class="nav-link" href="theme.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M19 11H5a2 2 0 00-2 2v2a2 2 0 002 2h2v3a1 1 0 001 1h3a1 1 0 001-1v-3h7a2 2 0 002-2v-2a2 2 0 00-2-2z"/><path d="M19 11V5a2 2 0 00-2-2h-2a2 2 0 00-2 2v6"/></svg>
<span class="nav-text">Theme</span>
<span class="badge badge-teal">New</span>
</a>
<a class="nav-link" href="typography.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><polyline points="4 7 4 4 20 4 20 7"/><line x1="9" y1="20" x2="15" y2="20"/><line x1="12" y1="4" x2="12" y2="20"/></svg>
<span class="nav-text">Typography</span>
</a>
<a class="nav-link" href="icons.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="10"/><path d="M8 14s1.5 2 4 2 4-2 4-2M9 9h.01M15 9h.01"/></svg>
<span class="nav-text">Icons</span>
</a>
<a class="nav-link" href="media_gallery.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="M21 15l-5-5L5 21"/></svg>
<span class="nav-text">Media</span>
</a>
</div>
<div class="nav-group">
<div class="nav-label">Admin</div>
<a class="nav-link" href="contacts.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="8" r="4"/><path d="M5 20c0-3.9 3.1-7 7-7s7 3.1 7 7"/></svg>
<span class="nav-text">Contacts</span>
</a>
<a class="nav-link" href="user_management.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
<span class="nav-text">User management</span>
</a>
<a class="nav-link" href="profile.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
<span class="nav-text">Your profile</span>
</a>
<a class="nav-link" href="settings.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3M5.6 5.6l2.1 2.1M16.3 16.3l2.1 2.1M5.6 18.4l2.1-2.1M16.3 7.7l2.1-2.1"/></svg>
<span class="nav-text">Settings</span>
</a>
<a class="nav-link" href="faq.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="10"/><path d="M9.1 9a3 3 0 015.8 1c0 2-3 3-3 3"/><circle cx="12" cy="17" r="0.5" fill="currentColor"/></svg>
<span class="nav-text">Help center</span>
</a>
</div>
<div class="nav-group">
<div class="nav-label">Layouts</div>
<a class="nav-link" href="fixed_sidebar.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 9v12"/></svg>
<span class="nav-text">Fixed sidebar</span>
</a>
<a class="nav-link" href="fixed_footer.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 9v12"/></svg>
<span class="nav-text">Fixed footer</span>
</a>
<a class="nav-link" href="level2.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="2" y="3" width="20" height="18" rx="2"/><path d="M2 8h20"/></svg>
<span class="nav-text">Nested page</span>
</a>
<a class="nav-link" href="plain_page.html">
<svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="2" y="3" width="20" height="18" rx="2"/><path d="M2 8h20"/></svg>
<span class="nav-text">Blank</span>
</a>
</div>
</nav>
<div class="sidebar-footer">
<div class="sidebar-user">
<div class="avatar">A<span class="online"></span></div>
<div class="sidebar-user-info">
<div class="name">Aigars Silkalns</div>
<div class="role">Admin</div>
</div>
<button class="more-btn" aria-label="More options">
<svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor"><circle cx="8" cy="3" r="1.2"/><circle cx="8" cy="8" r="1.2"/><circle cx="8" cy="13" r="1.2"/></svg>
</button>
</div>
</div>
</aside>
<header class="topbar">
<div class="topbar-left">
<button class="sidebar-toggle" type="button" aria-label="Open menu" aria-controls="sidebar" aria-expanded="false">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h16"/></svg>
</button>
<nav class="breadcrumb" aria-label="Breadcrumb"><span class="current" aria-current="page">Home</span></nav>
</div>
<div class="search-box">
<svg class="s-icon" width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><circle cx="7" cy="7" r="5"/><path d="M11 11l3.5 3.5"/></svg>
<input type="text" placeholder="Search pages or run a command…" aria-label="Open command palette">
<kbd>⌘K</kbd>
</div>
<div class="topbar-right">
<a class="tb-btn tb-docs" href="https://gentelella.colorlib.com/docs/" target="_blank" rel="noopener" title="Documentation">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path d="M4 4h11a4 4 0 014 4v13H8a4 4 0 01-4-4V4z"/><path d="M4 17a4 4 0 014-4h11"/></svg>
<span>Docs</span>
</a>
<button class="tb-btn theme-toggle" type="button" title="Toggle theme" aria-label="Toggle theme" aria-pressed="false">
<svg class="theme-icon-light" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/></svg>
<svg class="theme-icon-dark" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
</button>
<button class="tb-btn tb-notifications" type="button" title="Notifications" aria-label="Notifications" aria-haspopup="dialog" aria-expanded="false">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path d="M12 3a6 6 0 00-6 6c0 6-3 7-3 7h18s-3-1-3-7a6 6 0 00-6-6z"/><path d="M10.5 21a1.5 1.5 0 003 0"/></svg>
<span class="dot"></span>
</button>
<button class="tb-btn tb-messages" type="button" title="Messages" aria-label="Messages" aria-haspopup="dialog" aria-expanded="false">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="3"/><path d="M2 7l10 6 10-6"/></svg>
</button>
<button class="tb-avatar" type="button" aria-label="Account menu" aria-haspopup="menu" aria-expanded="false">A</button>
</div>
</header>
<main id="main-content" tabindex="-1" class="main">
<div class="page-wrapper">
<div class="page-header">
<div class="page-header-row">
<div>
<div class="page-pretitle">Developer</div>
<h1 class="page-title">Component playground</h1>
</div>
<div class="page-actions">
<a class="btn btn-outline" href="general_elements.html">All UI</a>
<a class="btn btn-outline" href="form.html">Forms</a>
<a class="btn btn-outline" href="theme.html">Theme generator</a>
</div>
</div>
</div>
<div class="banner banner-info">
<svg class="banner-icon" width="18" height="18" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="8" cy="8" r="6"/><path d="M8 5v.01M8 7v4"/></svg>
<div class="banner-body"><strong>Edit any code block live</strong> — type into it and the preview above updates in real time. Or click <strong>Copy</strong> to grab the HTML for your own page. Every component uses the v4 design tokens, so it'll match your theme out of the box.</div>
</div>
<div class="playground-layout">
<!-- Left rail: jump nav -->
<aside class="pg-nav">
<div class="pg-nav-label">Components</div>
<a class="pg-nav-link active" href="#buttons">Buttons</a>
<a class="pg-nav-link" href="#status">Status & badges</a>
<a class="pg-nav-link" href="#alerts">Alerts</a>
<a class="pg-nav-link" href="#cards">Cards</a>
<a class="pg-nav-link" href="#forms-basic">Form inputs</a>
<a class="pg-nav-link" href="#forms-advanced">Advanced forms</a>
<a class="pg-nav-link" href="#tables">Tables</a>
<a class="pg-nav-link" href="#tabs">Tabs</a>
<a class="pg-nav-link" href="#progress">Progress</a>
<a class="pg-nav-link" href="#stats">Stat tiles</a>
<a class="pg-nav-link" href="#timeline">Timeline</a>
<a class="pg-nav-link" href="#accordion">Accordion</a>
<a class="pg-nav-link" href="#empty">Empty state</a>
<div class="pg-nav-label" style="margin-top:14px">Async patterns</div>
<a class="pg-nav-link" href="#skeleton-table">Skeleton table</a>
<a class="pg-nav-link" href="#skeleton-tiles">Skeleton tiles</a>
<a class="pg-nav-link" href="#async-list">List lifecycle</a>
<a class="pg-nav-link" href="#submit-spinner">Submit spinner</a>
<a class="pg-nav-link" href="#banners">Banners</a>
<div class="pg-nav-label" style="margin-top:14px">Markup helpers</div>
<a class="pg-nav-link" href="#helpers-intro">Overview</a>
<a class="pg-nav-link" href="#helpers-stat">statTile()</a>
<a class="pg-nav-link" href="#helpers-status">statusBadge()</a>
<a class="pg-nav-link" href="#helpers-customer">customerCell()</a>
<a class="pg-nav-link" href="#helpers-activity">activityItem()</a>
<a class="pg-nav-link" href="#helpers-visitor">visitorRow()</a>
<a class="pg-nav-link" href="#helpers-empty">emptyState()</a>
</aside>
<div class="pg-content" id="pg-content">
<!-- Buttons -->
<section class="pg-block" id="buttons">
<h2>Buttons</h2>
<div class="pg-card" data-source>
<div class="pg-preview" data-preview>
<button class="btn btn-primary">Primary</button>
<button class="btn btn-outline">Outline</button>
<button class="btn btn-ghost">Ghost</button>
<button class="btn btn-danger">Danger</button>
<button class="btn btn-primary btn-sm">Small</button>
<button class="btn btn-primary" disabled>Disabled</button>
</div>
</div>
</section>
<!-- Status -->
<section class="pg-block" id="status">
<h2>Status & badges</h2>
<div class="pg-card" data-source>
<div class="pg-preview" data-preview>
<span class="status status-green">Active</span>
<span class="status status-yellow">Pending</span>
<span class="status status-red">Failed</span>
<span class="status status-blue">Info</span>
<span class="chip">Tag</span>
<span class="chip">Removable<button class="chip-close" aria-label="Remove">×</button></span>
</div>
</div>
</section>
<!-- Alerts -->
<section class="pg-block" id="alerts">
<h2>Alerts</h2>
<div class="pg-card" data-source>
<div class="pg-preview" data-preview style="display:flex;flex-direction:column;gap:10px;align-items:stretch">
<div class="alert alert-success">
<svg class="alert-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="8" cy="8" r="6"/><path d="M5 8l2 2 4-4"/></svg>
<div class="alert-body"><strong>Saved!</strong> Changes have been published.</div>
</div>
<div class="alert alert-warning">
<svg class="alert-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M8 2L1 14h14L8 2z"/><path d="M8 6v3M8 11v.01"/></svg>
<div class="alert-body"><strong>Heads up.</strong> API quota at 87%.</div>
</div>
<div class="alert alert-danger">
<svg class="alert-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="8" cy="8" r="6"/><path d="M5 5l6 6M11 5l-6 6"/></svg>
<div class="alert-body"><strong>Payment failed.</strong> Retry to continue.</div>
</div>
</div>
</div>
</section>
<!-- Cards -->
<section class="pg-block" id="cards">
<h2>Cards</h2>
<div class="pg-card" data-source>
<div class="pg-preview" data-preview style="display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px">
<div class="card">
<div class="card-header"><div class="card-title">Plain card</div></div>
<div class="card-body" style="font-size:13px;color:var(--text-secondary);line-height:1.5">A simple card with header and body. The most common building block.</div>
</div>
<div class="card">
<div class="card-header">
<div>
<div class="card-title">With subtitle</div>
<div class="card-subtitle">Plus an action</div>
</div>
<button class="btn btn-outline btn-sm">Action</button>
</div>
<div class="card-body" style="font-size:13px;color:var(--text-secondary);line-height:1.5">Header has room for actions on the right.</div>
</div>
</div>
</div>
</section>
<!-- Form inputs -->
<section class="pg-block" id="forms-basic">
<h2>Form inputs</h2>
<div class="pg-card" data-source>
<div class="pg-preview" data-preview style="display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px">
<div class="form-group">
<label class="form-label" for="pg-text">Text</label>
<input id="pg-text" class="form-control" type="text" placeholder="Type here…">
</div>
<div class="form-group">
<label class="form-label" for="pg-select">Select</label>
<select id="pg-select" class="form-control">
<option>Option A</option>
<option>Option B</option>
</select>
</div>
<div class="form-group">
<label class="form-label">Switch</label>
<label class="switch"><input type="checkbox" checked><span class="track"></span><span class="switch-label">Enabled</span></label>
</div>
<div class="form-group">
<label class="form-label">Segmented</label>
<div class="segmented">
<label><input type="radio" name="pg-seg" checked><span>Day</span></label>
<label><input type="radio" name="pg-seg"><span>Week</span></label>
<label><input type="radio" name="pg-seg"><span>Month</span></label>
</div>
</div>
</div>
</div>
</section>
<!-- Advanced forms -->
<section class="pg-block" id="forms-advanced">
<h2>Advanced form controls</h2>
<div class="pg-card" data-source data-source-label="Date-range picker">
<div class="pg-preview" data-preview style="max-width:340px">
<div class="date-range" data-date-range>
<input class="form-control" placeholder="Pick a date range" aria-label="Date range">
</div>
</div>
</div>
<div class="pg-card" data-source data-source-label="Multi-select">
<div class="pg-preview" data-preview style="max-width:480px">
<div class="multi-select" data-multi-select data-options="Design,Engineering,Product,Marketing,Support,Sales,Operations,Legal,Finance,HR">
<select multiple hidden>
<option value="Design" selected>Design</option>
<option value="Engineering" selected>Engineering</option>
<option value="Product">Product</option>
<option value="Marketing">Marketing</option>
<option value="Support">Support</option>
<option value="Sales">Sales</option>
<option value="Operations">Operations</option>
<option value="Legal">Legal</option>
<option value="Finance">Finance</option>
<option value="HR">HR</option>
</select>
</div>
</div>
</div>
<div class="pg-card" data-source data-source-label="Rich text editor">
<div class="pg-preview" data-preview>
<div class="rich-text" data-rich-text>
<textarea hidden><p>Click any button in the toolbar — <strong>bold</strong>, <em>italic</em>, lists, links, code blocks. Try <kbd>⌘B</kbd> / <kbd>⌘I</kbd> / <kbd>⌘K</kbd>.</p></textarea>
</div>
</div>
</div>
</section>
<!-- Tables -->
<section class="pg-block" id="tables">
<h2>Tables</h2>
<div class="pg-card" data-source>
<div class="pg-preview" data-preview>
<table class="table">
<thead><tr><th>Name</th><th>Plan</th><th>Status</th><th style="text-align:right">MRR</th></tr></thead>
<tbody>
<tr><td><div class="cell-customer"><div class="cell-avatar" style="background:var(--primary)">SK</div><span class="cell-strong">Sarah K.</span></div></td><td><span class="chip">Pro</span></td><td><span class="status status-green">Active</span></td><td class="cell-strong" style="text-align:right">$199</td></tr>
<tr><td><div class="cell-customer"><div class="cell-avatar" style="background:var(--azure)">MR</div><span class="cell-strong">Michael R.</span></div></td><td><span class="chip">Business</span></td><td><span class="status status-green">Active</span></td><td class="cell-strong" style="text-align:right">$499</td></tr>
<tr><td><div class="cell-customer"><div class="cell-avatar" style="background:var(--yellow)">EW</div><span class="cell-strong">Emily W.</span></div></td><td><span class="chip">Starter</span></td><td><span class="status status-yellow">Pending</span></td><td class="cell-strong" style="text-align:right">$49</td></tr>
</tbody>
</table>
</div>
</div>
</section>
<!-- Tabs -->
<section class="pg-block" id="tabs">
<h2>Tabs</h2>
<div class="pg-card" data-source>
<div class="pg-preview" data-preview>
<div class="chart-tabs">
<button class="chart-tab active">Overview</button>
<button class="chart-tab">Activity</button>
<button class="chart-tab">Settings</button>
</div>
</div>
</div>
</section>
<!-- Progress -->
<section class="pg-block" id="progress">
<h2>Progress</h2>
<div class="pg-card" data-source>
<div class="pg-preview" data-preview style="display:flex;flex-direction:column;gap:14px;align-items:stretch">
<div>
<div style="display:flex;justify-content:space-between;font-size:12.5px;margin-bottom:4px"><span>Storage</span><span style="color:var(--text-muted)">62 / 100 GB</span></div>
<div class="progress-thin"><div class="bar" style="width:62%;background:var(--primary)"></div></div>
</div>
<div>
<div style="display:flex;justify-content:space-between;font-size:12.5px;margin-bottom:4px"><span>API quota</span><span style="color:var(--text-muted)">87,400 / 100,000</span></div>
<div class="progress-thin"><div class="bar" style="width:87%;background:var(--yellow)"></div></div>
</div>
<div class="loading-bar" style="height:3px;background:var(--bg-surface-secondary);border-radius:3px;overflow:hidden"></div>
</div>
</div>
</section>
<!-- Stat tiles -->
<section class="pg-block" id="stats">
<h2>Stat tiles</h2>
<div class="pg-card" data-source>
<div class="pg-preview" data-preview style="display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px">
<div class="card"><div class="stat">
<div class="stat-icon teal"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M12 1v22M5 8l7-7 7 7"/></svg></div>
<div class="stat-content">
<div class="stat-label">Active users</div>
<div class="stat-value-row"><span class="stat-value">8,432</span><span class="stat-change up">↑ 14%</span></div>
<div class="stat-subtext">vs last week</div>
</div>
</div></div>
<div class="card"><div class="stat">
<div class="stat-icon red"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M3 3v18h18"/><path d="M19 9l-5 5-4-4-3 3"/></svg></div>
<div class="stat-content">
<div class="stat-label">Churn</div>
<div class="stat-value-row"><span class="stat-value">2.4%</span><span class="stat-change down">↓ 0.4pp</span></div>
<div class="stat-subtext">improving</div>
</div>
</div></div>
</div>
</div>
</section>
<!-- Timeline -->
<section class="pg-block" id="timeline">
<h2>Timeline</h2>
<div class="pg-card" data-source>
<div class="pg-preview" data-preview>
<div class="timeline">
<div class="timeline-item is-primary">
<div class="ti-time">Just now</div>
<div class="ti-title">Deployment succeeded</div>
<div class="ti-desc">v4.0.2 in production · 28s</div>
</div>
<div class="timeline-item is-blue">
<div class="ti-time">14 min ago</div>
<div class="ti-title">PR #248 merged</div>
</div>
<div class="timeline-item is-yellow">
<div class="ti-time">3 hours ago</div>
<div class="ti-title">Review requested</div>
</div>
</div>
</div>
</div>
</section>
<!-- Accordion -->
<section class="pg-block" id="accordion">
<h2>Accordion</h2>
<div class="pg-card" data-source>
<div class="pg-preview" data-preview>
<div class="accordion">
<details class="accordion-item" open>
<summary class="accordion-summary">First panel
<svg class="chev" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M4 6l4 4 4-4"/></svg>
</summary>
<div class="accordion-content">Content for the first panel goes here.</div>
</details>
<details class="accordion-item">
<summary class="accordion-summary">Second panel
<svg class="chev" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M4 6l4 4 4-4"/></svg>
</summary>
<div class="accordion-content">Click the chevron to expand.</div>
</details>
</div>
</div>
</div>
</section>
<!-- Empty state -->
<section class="pg-block" id="empty">
<h2>Empty state</h2>
<div class="pg-card" data-source>
<div class="pg-preview" data-preview>
<div class="empty-state">
<div class="empty-state-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 8l9 6 9-6"/></svg>
</div>
<div class="empty-state-title">No messages yet</div>
<div class="empty-state-text">When you receive messages, they'll show up here.</div>
<div class="empty-state-actions">
<button class="btn btn-primary btn-sm">Compose</button>
</div>
</div>
</div>
</div>
</section>
<!-- ── Async patterns ──────────────────────────────────────────── -->
<section class="pg-block" id="async-intro">
<div class="banner banner-info" style="margin-bottom:14px">
<svg class="banner-icon" width="18" height="18" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="8" cy="8" r="6"/><path d="M8 5v.01M8 7v4"/></svg>
<div class="banner-body"><strong>Async patterns.</strong> The four states every list/grid passes through: <em>loading → loaded</em>, or <em>loading → empty</em>, or <em>loading → error</em>. Wire all four and your app feels solid even on flaky networks. The data-adapter pattern in <code>src/v4/data-adapter.js</code> hands you the data; the components below are what you render in each state.</div>
</div>
</section>
<section class="pg-block" id="skeleton-table">
<h2>Skeleton table</h2>
<p style="font-size:13px;color:var(--text-secondary);margin:0 0 12px;line-height:1.55">Render placeholder rows while data loads. Width variation across columns prevents the "jelly bean" look. Fades in via the <code>.skeleton</code> shimmer animation defined in <code>_components.scss</code>.</p>
<div class="pg-card" data-source>
<div class="pg-preview" data-preview>
<table class="table" style="width:100%">
<thead><tr><th>Customer</th><th>Plan</th><th>Status</th><th style="text-align:right">MRR</th></tr></thead>
<tbody>
<tr><td><span class="skeleton skeleton-text" style="width:65%"></span></td><td><span class="skeleton skeleton-text" style="width:50%"></span></td><td><span class="skeleton skeleton-text" style="width:40%"></span></td><td><span class="skeleton skeleton-text" style="width:30%;display:inline-block"></span></td></tr>
<tr><td><span class="skeleton skeleton-text" style="width:80%"></span></td><td><span class="skeleton skeleton-text" style="width:45%"></span></td><td><span class="skeleton skeleton-text" style="width:55%"></span></td><td><span class="skeleton skeleton-text" style="width:35%;display:inline-block"></span></td></tr>
<tr><td><span class="skeleton skeleton-text" style="width:55%"></span></td><td><span class="skeleton skeleton-text" style="width:60%"></span></td><td><span class="skeleton skeleton-text" style="width:50%"></span></td><td><span class="skeleton skeleton-text" style="width:40%;display:inline-block"></span></td></tr>
<tr><td><span class="skeleton skeleton-text" style="width:70%"></span></td><td><span class="skeleton skeleton-text" style="width:55%"></span></td><td><span class="skeleton skeleton-text" style="width:42%"></span></td><td><span class="skeleton skeleton-text" style="width:32%;display:inline-block"></span></td></tr>
</tbody>
</table>
</div>
</div>
</section>
<section class="pg-block" id="skeleton-tiles">
<h2>Skeleton tiles</h2>
<p style="font-size:13px;color:var(--text-secondary);margin:0 0 12px;line-height:1.55">Use for card grids — dashboards, file managers, product galleries. Avatar circle + headline + 2 lines is the canonical shape.</p>
<div class="pg-card" data-source>
<div class="pg-preview" data-preview style="display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px">
<div class="card" style="padding:16px">
<span class="skeleton skeleton-circle" style="width:32px;height:32px;margin-bottom:10px"></span>
<span class="skeleton skeleton-text skeleton-text-lg" style="width:60%"></span>
<span class="skeleton skeleton-text" style="width:90%"></span>
<span class="skeleton skeleton-text" style="width:75%;margin-bottom:0"></span>
</div>
<div class="card" style="padding:16px">
<span class="skeleton skeleton-circle" style="width:32px;height:32px;margin-bottom:10px"></span>
<span class="skeleton skeleton-text skeleton-text-lg" style="width:50%"></span>
<span class="skeleton skeleton-text" style="width:85%"></span>
<span class="skeleton skeleton-text" style="width:65%;margin-bottom:0"></span>
</div>
<div class="card" style="padding:16px">
<span class="skeleton skeleton-circle" style="width:32px;height:32px;margin-bottom:10px"></span>
<span class="skeleton skeleton-text skeleton-text-lg" style="width:70%"></span>
<span class="skeleton skeleton-text" style="width:80%"></span>
<span class="skeleton skeleton-text" style="width:55%;margin-bottom:0"></span>
</div>
</div>
</div>
</section>
<section class="pg-block" id="async-list">
<h2>List lifecycle — interactive</h2>
<p style="font-size:13px;color:var(--text-secondary);margin:0 0 12px;line-height:1.55">Click a button below to simulate each state. This is exactly what <a href="orders.html?api=1">orders.html</a> and the inbox use under the hood.</p>
<div class="pg-card">
<div class="pg-preview" data-preview style="flex-direction:column;align-items:stretch;gap:0;padding:0">
<div style="display:flex;gap:6px;padding:14px 16px;border-bottom:1px solid var(--border-color-light);flex-wrap:wrap">
<button class="btn btn-outline btn-sm" data-lifecycle="success">Loading → success</button>
<button class="btn btn-outline btn-sm" data-lifecycle="empty">Loading → empty</button>
<button class="btn btn-outline btn-sm" data-lifecycle="error">Loading → error</button>
<button class="btn btn-ghost btn-sm" data-lifecycle="reset">Reset</button>
</div>
<div id="async-list-host" style="padding:14px 16px;min-height:200px"></div>
</div>
</div>
</section>
<section class="pg-block" id="submit-spinner">
<h2>Submit spinner</h2>
<p style="font-size:13px;color:var(--text-secondary);margin:0 0 12px;line-height:1.55">Disable the button + swap label for a spinner during the request. Re-enable + restore label when it resolves. Click below to simulate a 1.5s submit.</p>
<div class="pg-card" data-source>
<div class="pg-preview" data-preview>
<form id="submit-spinner-form" style="display:flex;gap:10px;align-items:center;flex-wrap:wrap" onsubmit="return false">
<input class="form-control" placeholder="Type something" style="width:260px" aria-label="Sample input" required>
<button type="submit" class="btn btn-primary" data-pg-submit>
<span class="btn-spinner spinner spinner-sm" hidden style="border-top-color:#fff;margin-right:6px"></span>
<span data-pg-submit-label>Save</span>
</button>
<span style="font-size:12px;color:var(--text-muted)">↑ Click "Save"</span>
</form>
</div>
</div>
</section>
<section class="pg-block" id="banners">
<h2>Banners — feedback at the page level</h2>
<p style="font-size:13px;color:var(--text-secondary);margin:0 0 12px;line-height:1.55">For things the user needs to see and may want to act on (failed payment, quota near limit). For ephemeral feedback (saved, copied, deleted) use a toast instead — see <a href="general_elements.html#toasts">general elements</a>.</p>
<div class="pg-card" data-source>
<div class="pg-preview" data-preview style="flex-direction:column;align-items:stretch;gap:10px">
<div class="banner">
<svg class="banner-icon" width="18" height="18" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="8" cy="8" r="6"/><path d="M5 8l2 2 4-4"/></svg>
<div class="banner-body"><strong>Saved.</strong> Changes are live.</div>
</div>
<div class="banner banner-info">
<svg class="banner-icon" width="18" height="18" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="8" cy="8" r="6"/><path d="M8 5v.01M8 7v4"/></svg>
<div class="banner-body"><strong>Heads up.</strong> Maintenance window scheduled for Friday 02:00 UTC.</div>
</div>
<div class="banner banner-warning">
<svg class="banner-icon" width="18" height="18" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M8 1l7 13H1L8 1z"/><path d="M8 6v4"/></svg>
<div class="banner-body"><strong>API quota at 87%.</strong> You'll hit the cap by Friday.</div>
<div class="banner-actions"><button class="btn btn-outline btn-sm">Upgrade plan</button></div>
</div>
<div class="banner banner-danger">
<svg class="banner-icon" width="18" height="18" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="8" cy="8" r="6"/><path d="M5 5l6 6M11 5l-6 6"/></svg>
<div class="banner-body"><strong>Payment failed.</strong> Update your card to keep your subscription active.</div>
<div class="banner-actions"><button class="btn btn-outline btn-sm">Update card</button></div>
</div>
</div>
</div>
</section>
<section class="pg-block" id="helpers-intro">
<h2>Markup helpers — stop hand-writing scaffolds</h2>
<p style="font-size:13px;color:var(--text-secondary);margin:0 0 8px;line-height:1.55">For pages that build content from data (orders, inbox threads, kanban cards…) the boilerplate adds up. <code>src/v4/markup.js</code> exposes pure functions that return HTML strings — no framework, no virtual DOM. Auto-escapes user content. Drop the result into <code>innerHTML</code> or interpolate into a template literal.</p>
<p style="font-size:13px;color:var(--text-secondary);margin:0 0 12px;line-height:1.55">Each helper below shows the call site (top) and the rendered output (bottom).</p>
</section>
<section class="pg-block" id="helpers-stat">
<h3 style="margin:0 0 10px;font-size:15px">statTile()</h3>
<pre class="pg-code" style="margin-bottom:12px"><code>import { statTile } from '/src/v4/markup.js';
document.querySelector('#stats').innerHTML = [
statTile({ label: 'Revenue', value: '$84,520', color: 'green',
change: { pct: '+18%', direction: 'up' }, subtext: '$3,218 today' }),
statTile({ label: 'Pending', value: '42', color: 'yellow',
change: { pct: '-3%', direction: 'down' }, subtext: '5 awaiting payment' })
].join('');</code></pre>
<div id="helpers-stat-host" class="row col-2" style="gap:12px"></div>
</section>
<section class="pg-block" id="helpers-status">
<h3 style="margin:0 0 10px;font-size:15px">statusBadge()</h3>
<pre class="pg-code" style="margin-bottom:12px"><cod