
Interactive Dashboard Builder
Ship a single HTML file with Chart.js charts, KPI rows, and dropdown filters that stakeholders can open offline or attach to a report.
Overview
Interactive Dashboard Builder is an agent skill most often used in Build (also Validate, Grow) that produces self-contained interactive HTML reports with Chart.js charts and dropdown filters.
Install
npx skills add https://github.com/anthropics/knowledge-work-plugins --skill interactive-dashboard-builderWhat is this skill?
- Self-contained HTML dashboards with Chart.js 4.5.1 and chartjs-adapter-date-fns from CDN integrity pins
- Reusable base template: header, KPI row, filter controls, and chart grid sections
- Dropdown and interactive filters without a backend server
- Professional styling patterns for shareable executive or product reports
- Base template uses Chart.js 4.5.1 with SRI integrity attributes on CDN scripts
Adoption & trust: 596 installs on skills.sh; 19.6k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You have metrics in CSV or JSON but no fast way to hand stakeholders an interactive chart deck without deploying a web app.
Who is it for?
Indie SaaS founders and operators who need one-off or recurring static dashboards for investors, customers, or internal reviews.
Skip if: Products that need live database connections, role-based auth, or a maintained React analytics product.
When should I use this skill?
User wants dashboards, interactive reports, or shareable HTML files with charts and filters that work without a server.
What do I get? / Deliverables
You get a single shareable HTML file with filters, KPI tiles, and Chart.js visualizations that run without a server.
- Single self-contained HTML dashboard file
- Chart.js configs with header filters and KPI section markup
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
Frontend is the canonical shelf because output is self-contained HTML/CSS/JS with Chart.js—not a hosted BI server. frontend subphase covers client-side presentation layers solo builders can email or drop on static hosting.
Where it fits
Mock a funnel dashboard from sample CSV to test narrative before investing in a live analytics stack.
Assemble KPI rows and time-series charts into one HTML file for a quarterly business review.
Refresh cohort charts with new export data and ship an updated static dashboard to email lists.
How it compares
Static Chart.js skill template, not a hosted BI platform or MCP data warehouse connector.
Common Questions / FAQ
Who is interactive-dashboard-builder for?
Solo builders and small teams who need browser-openable dashboards and interactive reports without backend infrastructure.
When should I use interactive-dashboard-builder?
During Validate prototype when demoing metrics, during Build frontend when packaging a report UI, and during Grow analytics when refreshing lifecycle or funnel views for stakeholders.
Is interactive-dashboard-builder safe to install?
It generates local HTML using pinned CDN scripts; review the Security Audits panel on this Prism page and audit any embedded data before sharing files externally.
SKILL.md
READMESKILL.md - Interactive Dashboard Builder
# Interactive Dashboard Builder Skill Patterns and techniques for building self-contained HTML/JS dashboards with Chart.js, filters, interactivity, and professional styling. ## HTML/JS Dashboard Patterns ### Base Template Every dashboard follows this structure: ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Dashboard Title</title> <script src="https://cdn.jsdelivr.net/npm/chart.js@4.5.1" integrity="sha384-jb8JQMbMoBUzgWatfe6COACi2ljcDdZQ2OxczGA3bGNeWe+6DChMTBJemed7ZnvJ" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns@3.0.0" integrity="sha384-cVMg8E3QFwTvGCDuK+ET4PD341jF3W8nO1auiXfuZNQkzbUUiBGLsIQUE+b1mxws" crossorigin="anonymous"></script> <style> /* Dashboard styles go here */ </style> </head> <body> <div class="dashboard-container"> <header class="dashboard-header"> <h1>Dashboard Title</h1> <div class="filters"> <!-- Filter controls --> </div> </header> <section class="kpi-row"> <!-- KPI cards --> </section> <section class="chart-row"> <!-- Chart containers --> </section> <section class="table-section"> <!-- Data table --> </section> <footer class="dashboard-footer"> <span>Data as of: <span id="data-date"></span></span> </footer> </div> <script> // Embedded data const DATA = []; // Dashboard logic class Dashboard { constructor(data) { this.rawData = data; this.filteredData = data; this.charts = {}; this.init(); } init() { this.setupFilters(); this.renderKPIs(); this.renderCharts(); this.renderTable(); } applyFilters() { // Filter logic this.filteredData = this.rawData.filter(row => { // Apply each active filter return true; // placeholder }); this.renderKPIs(); this.updateCharts(); this.renderTable(); } // ... methods for each section } const dashboard = new Dashboard(DATA); </script> </body> </html> ``` ### KPI Card Pattern ```html <div class="kpi-card"> <div class="kpi-label">Total Revenue</div> <div class="kpi-value" id="kpi-revenue">$0</div> <div class="kpi-change positive" id="kpi-revenue-change">+0%</div> </div> ``` ```javascript function renderKPI(elementId, value, previousValue, format = 'number') { const el = document.getElementById(elementId); const changeEl = document.getElementById(elementId + '-change'); // Format the value el.textContent = formatValue(value, format); // Calculate and display change if (previousValue && previousValue !== 0) { const pctChange = ((value - previousValue) / previousValue) * 100; const sign = pctChange >= 0 ? '+' : ''; changeEl.textContent = `${sign}${pctChange.toFixed(1)}% vs prior period`; changeEl.className = `kpi-change ${pctChange >= 0 ? 'positive' : 'negative'}`; } } function formatValue(value, format) { switch (format) { case 'currency': if (value >= 1e6) return `$${(value / 1e6).toFixed(1)}M`; if (value >= 1e3) return `$${(value / 1e3).toFixed(1)}K`; return `$${v