Embed an Editable Dashboard in Your React, Vue or Angular App

One npm package with a grid layout engine, a widget wizard and a JSON config you can store

By Vincenzo Manto, founder of Datastripes · Published 19 October 2026 · Updated 19 October 2026
Customers like dashboards they can rearrange. Building one yourself means a grid system, a catalog of charts, a settings form, filters and a way to save the layout, and that list is longer than it looks from the outside.@datastripes/dashboard packages those pieces. You pass it an array of rows and a JSON config, and it renders a dashboard that users can edit, filter and export. This page covers how the config works, how to embed the dashboard in each framework, and what the package leaves to you.

One package, four entry points

The root entry, @datastripes/dashboard, is the core engine: schema, query engine, grid engine, store, widget logic and licensing. It needs nothing else. On top of it sit a React entry with a <DatastripesDashboard> component (React 19), a Vue entry for Vue 3.4 and later, an Angular entry with a standalone DatastripesDashboardComponent (Angular 18 or 19), and an /elements entry that registers a <datastripes-dashboard> custom element.The UI frameworks are optional peer dependencies, so installing the package never pulls one in.
npm install @datastripes/dashboard

The dashboard is a JSON document

Everything about a dashboard lives in one config object: a version, settings with the grid layout, global filters, calculated fields, column labels and a list of widgets. Each widget has a type, a position on the grid and a query.
import { DashboardStore, JsQueryEngine, parseDashboardConfig } from '@datastripes/dashboard';

const config = parseDashboardConfig({
  version: '1.0.0',
  settings: { title: 'Sales', layout: { columns: 12, rowHeight: 60, gutter: 16 } },
  globalFilters: [],
  calculatedFields: [],
  columnLabels: {},
  widgets: [
    {
      id: 'kpi_revenue',
      type: 'kpi_card',
      title: 'Total Revenue',
      grid: { x: 0, y: 0, w: 3, h: 2 },
      dataQuery: { metrics: [{ field: 'amount', aggregation: 'sum', alias: 'amount' }] },
      renderConfig: { format: 'currency' },
    },
  ],
});

const store = new DashboardStore({ config, data: myRows, engine: new JsQueryEngine() });
The grid here is twelve columns wide with 60 pixel rows. The single widget sits at the top left corner, three columns wide and two rows tall, and sums the amount column. Because the config is plain JSON, you can store it next to the user's account and load it back later.

Embedding it in React

In React the config and the data go in as props. In edit mode the user can change the layout, and the component reports every change back to you.
import { DatastripesDashboard } from '@datastripes/dashboard/react';
import type { DashboardConfig } from '@datastripes/dashboard';

function App() {
  const [config, setConfig] = useState<DashboardConfig | undefined>();

  return (
    <DatastripesDashboard
      data={myRows}
      config={config}
      mode="edit"
      apiKey={import.meta.env.VITE_DATASTRIPES_KEY}
      onChange={setConfig}
      onSave={(saved) => persistToBackend(saved)}
      onAction={(event) => console.log(event)}
    />
  );
}
In edit mode the toolbar has an Add widget button that opens a short wizard. The user picks a widget type, then a chart kind from the catalog of 25, then fields, colors and axis labels. The gear icon on an existing widget reopens the same form. The toolbar also offers a light and dark switch, PDF export and a period navigator.onSave fires when the user clicks Save, which is where you persist the config. onAction delivers row_click and filter_change events, which is how you connect drill-down and cross-filtering to the rest of your app.

What users can change without you

The settings panel lets users adjust number formatting, define calculated fields and rename columns. That covers a lot of the requests that usually come back to a developer: show this as a percentage, add a margin column, call the field something readable. Because those choices end up in the config, they are saved and restored with the layout.Filters work at two levels. Global filters in the config apply across the dashboard, and a filter panel widget lets the user change them in place.

Vue, Angular and plain HTML

Vue uses a DatastripesDashboard single file component and Angular a standalone DatastripesDashboardComponent. For any other stack the custom element works straight from a script tag.
<script src="https://unpkg.com/@datastripes/dashboard/dist/elements/index.global.js"></script>
<datastripes-dashboard id="dash" mode="edit" api-key="..."></datastripes-dashboard>
<script>
  const el = document.getElementById('dash');
  el.data = myRows;       // set as a property for large datasets
  el.config = myConfig;   // DashboardConfig object
  el.addEventListener('ds-change', (e) => console.log(e.detail));
  el.addEventListener('ds-action', (e) => console.log(e.detail));
</script>

Storing dashboards and building your own layout

Keep the config as JSON in whatever table holds your user settings, one row per dashboard. The config carries a version field, so when the format changes you can tell which shape a stored dashboard has and migrate it.If the full component is more than you need, the pieces are exported separately: the toolbar, the add widget and settings modals, the KPI card, chart and table widgets, the filter panel, a markdown widget and the frame that provides drag and resize handles around any widget. That lets you compose your own page around the same engine.

Using the engine without any UI

Everything a framework wrapper does, including querying, filtering, grid layout and licensing, is a call into the core. That means you can compute a dashboard's results on a server and hydrate a framework component with them later.The dashboard takes its data as an array of rows. Fetching those rows and shaping them is your job, which keeps the package independent of your database and your API.

What the trial tier limits

Without a valid apiKey every dashboard runs in a restricted trial. The dataset is silently cut to its first 1,000 rows, the PDF export button is disabled and a banner states the row cap. The cap lives in the store itself, so it applies the same way in React, Vue, Angular and the custom element.Some chart types also need a valid license. Heatmaps, graphs, sankey diagrams, parallel coordinates, gauges, funnels, candlesticks, box plots and calendar heatmaps are gated, so check that the charts you plan to ship are available on the plan you buy.

Where it is the wrong tool

This is a component for dashboards inside your own product. It does not replace a data warehouse or a hosted BI server. Everything is computed in the browser from the rows you pass in, so very large datasets should be aggregated before they reach it.If your users need scheduled email reports or governed metrics shared across a whole company, a full BI platform is the better fit.

Questions people ask