@richardmcquiston01/dashboard-widgets-toolkit

Framework-agnostic dashboard widget toolkit: typed widget definitions and data payloads (KPI, gauge, table, bar list, alert list, chart), user layout (order, hide, minimise), and React renderers. Bring your own data providers.
3,815
Install
npm install @richardmcquiston01/dashboard-widgets-toolkit
Latest Version:0.34.0
Vue:3
License:Apache-2.0
Last Updated:Oct 21, 2026
Links: GitHub  ·  npm
Maintainer: richardmcquiston01

Dashboard Widgets Toolkit

Table of Contents

| Overview | Getting Started | Widget Kinds | More Information | Buy Me a Coffee | License | Copyright |

Overview

@richardmcquiston01/dashboard-widgets-toolkit helps you build dashboards out of widgets. A widget is one card on the dashboard, such as a number, a meter, a table, or a chart. The toolkit works with any framework and includes React components that draw the widgets.

It gives you:

  • Typed widget definitions and data payloads. A payload is the data one widget shows.
  • A layout that each viewer can change. They can reorder (by buttons, or by dragging with the draggable prop), hide, and minimize widgets.
  • React renderers, including accessible charts drawn as Scalable Vector Graphics (SVG), each with a "View as table" twin.
  • Controls for viewers, all saved in the layout: an edit mode, pages of widgets, and an Options dialog for each widget's title, width, view and options. A viewer can also duplicate a widget into a clone with its own settings.
  • Dashboard-level filters (a date range, a store, a segment) chosen once in a filter bar and passed to every provider, with option-aware cache keys and reloads only for the widgets that use a changed filter.
  • Locks that keep chosen widgets in place, a detail view with search, sort and paging, and CSS-variable theming with a WidgetTheme wrapper, contrast and color-vision checks, and presets.
  • Export: CSV for tables, bar lists, charts and the detail view, SVG and PNG download for charts (exportFormats), and a print stylesheet.
  • Freshness: an "Updated 2 minutes ago" line and a refresh button on each card (freshness, onRefresh), and a failed refresh keeps the last good data with a badge.
  • Storage helpers (an adapter contract and a useStoredLayout hook) so you can keep layouts in localStorage, a database or a server.

You bring your own data. The package never fetches or stores anything. You register a provider for each widget, such as a database query, a web request, or a computed value. You also save each viewer's layout wherever you like. Payloads are plain JavaScript Object Notation (JSON), so a server can resolve widgets and a browser can check and draw them.

The package has five parts:

Import path What it is
@richardmcquiston01/dashboard-widgets-toolkit (or /core) Runtime-neutral core (Node, Bun, browsers): definitions, payload types, validators, resolveWidgets, layout, formatting. No DOM, no network, no storage.
@richardmcquiston01/dashboard-widgets-toolkit/builder Headless Widget Builder: describe a provider (defineSource), then create and edit a widget definition as JSON with functions that never return an invalid one.
@richardmcquiston01/dashboard-widgets-toolkit/react React (18+) renderers: WidgetCard, one renderer per kind, WidgetGrid, a layout-aware Dashboard, and accessible inline-SVG charts with a "View as table" twin.
@richardmcquiston01/dashboard-widgets-toolkit/vue Vue (3.3+) renderers over the same core and class names: WidgetCard, ResolvedWidgetCard, one renderer per kind, an SVG chart with a "View as table" twin, a layout-aware Dashboard with pages, and useWidgets / useStoredLayout.
@richardmcquiston01/dashboard-widgets-toolkit/styles.css Optional stylesheet. Components are unstyled by default and carry stable dwt-* class names.

Back to Top

Getting Started

The Getting Started guide has the full walkthrough and more than a dozen examples. The short version is below.

Prerequisites

  • Node.js 18 or newer, or Bun 1.3 or newer (or any modern browser bundler)
  • React 18 or newer, only if you use /react
  • Vue 3.3 or newer, only if you use /vue
  • TypeScript is optional. Type declarations are included.

Installation

bun add @richardmcquiston01/dashboard-widgets-toolkit
# or
npm install @richardmcquiston01/dashboard-widgets-toolkit

Usage

Define your widgets, write a provider for each one, then resolve them. A failing provider never breaks the dashboard. That widget comes back with an error message and the others still load.

import {
  defineWidget,
  resolveWidgets,
  type WidgetContext,
  type WidgetProviders,
} from '@richardmcquiston01/dashboard-widgets-toolkit';

interface ShopContext extends WidgetContext {
  shopId: string;
}

const widgets = [
  defineWidget({ key: 'revenue', title: 'Revenue', kind: 'KPI', sortOrder: 10 }),
];

const providers: WidgetProviders<ShopContext> = {
  revenue: async ({ shopId }) => {
    const { current, previous } = await loadRevenue(shopId); // your code
    return {
      kind: 'KPI',
      value: current,
      previous,
      format: 'currency',
      label: 'Revenue',
    };
  },
};

const resolved = await resolveWidgets(widgets, providers, {
  shopId: 'shop-1',
  roles: ['owner'], // widgets limited to other roles are skipped
});

To show the result in React, pass the resolved widgets to the Dashboard component:

import { Dashboard } from '@richardmcquiston01/dashboard-widgets-toolkit/react';
import '@richardmcquiston01/dashboard-widgets-toolkit/styles.css'; // optional

<Dashboard widgets={resolved} />;

Without onLayoutChange, the dashboard is read-only. The guide shows how to let viewers move, hide, and minimize widgets and how to save their layout.

Examples

The Getting Started guide covers these, and more:

Back to Top

Widget Kinds

Kind Payload fields Typical use
TEXT value: string, label A count or status as text
KPI value: number, previous?: number | null, format, currency?, label, hint?, higherIsBetter? Stat tile with a change vs previous period
GAUGE value, max, label A meter (unread of total, quota used)
TABLE columns: {label, numeric?, type?, formatter?}[], rows: {text, href?, value?}[][], footer? Small data tables
BAR_LIST items: {label, value, display?}[], total? Ratings breakdown, purchases by country
ALERT_LIST items: {title, href?, thumbnailUrl?, valueLabel, detail?}[], total, emptyText Low stock, stale listings, expiring soon
GRAPH series: {name, points: {label, value}[]}[], chartType: 'bar' | 'line', valueFormat, currency?, xLabel? Revenue by month, views per day

KPI stands for Key Performance Indicator.

format and valueFormat are 'number' | 'currency' | 'percent'. Money is in major units (12.5 is $12.50). Percents are fractions (0.25 is 25%). Any widget may return an empty state instead: { empty: true, text: 'No orders synced yet.' }.

A TABLE cell's optional value (a string or number) is what the card's table controls and the detail view sort and search on. Use it when text is made for reading, such as a timestamp behind "3 days ago", a rating behind stars, or an amount behind "$1,234.00". The tableControls setting on the widget definition turns the controls on.

Back to Top

More Information

Back to Top

Buy Me a Coffee

If this app, code, or repository has helped you or someone you know, please consider donating. I appreciate any help to offset the costs of development and/or AI Credits.

Donate via Stripe, or scan:

Donate via Stripe

Back to Top

License

Apache 2

Back to Top

(c)2026 Richard McQuiston. All rights reserved.

Back to Top

Related Packages

vue-advanced-speedometer-pro

A high-quality, advanced Vue 3 speedometer/gauge chart component with multiple g...

1,005
vue-circular-gauge

Circular gauge component for Vue.js with customizable colors, animations, and th...

4,173 21
@qlik/sprout-icons

Comprehensive icon library for the Sprout Design System, available as React and...

578,832
gridstack

TypeScript/JS lib for dashboard layout and creation, responsive, mobile support,...

21,312,447 9,205
@homarr/gridstack

TypeScript/JS lib for dashboard layout and creation, responsive, mobile support,...

72,072 0

Version History

Version Released License
0.34.0 Apache-2.0
0.33.0 Apache-2.0
0.32.0 Apache-2.0
0.31.0 Apache-2.0
0.30.0 Apache-2.0