npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@jmars25/pivottable-ts

v1.0.1

Published

TypeScript pivot table with drag-and-drop, vanilla adapter, Chart.js renderers and 15-language locale support

Readme

pivottable-ts

A TypeScript pivot table library with drag-and-drop UI, Chart.js renderers, and 15-language locale support. Framework-agnostic — works with vanilla JS, React, Vue, or any other stack.

Forked from the original pivottable by Nicolas Kruchten and rewritten in TypeScript with a vanilla adapter (no jQuery required), columnar and streaming data input, and a modern build pipeline.


Installation

npm install @jmars25/pivottable-ts

For Chart.js renderers:

npm install chart.js

Quick start

Static table

import { createPivot } from "@jmars25/pivottable-ts/vanilla";
import "@jmars25/pivottable-ts/dist/pivot.css";

const data = [
  { Region: "North", Product: "Widget", Sales: 120 },
  { Region: "South", Product: "Gadget", Sales: 340 },
  // ...
];

createPivot(document.getElementById("output"), data, {
  rows: ["Region"],
  cols: ["Product"],
  vals: ["Sales"],
});

Interactive drag-and-drop UI

import { createPivotUI } from "@jmars25/pivottable-ts/vanilla";
import "@jmars25/pivottable-ts/dist/pivot.css";

const handle = createPivotUI(document.getElementById("output"), data, {
  rows: ["Region"],
  cols: ["Product"],
  vals: ["Sales"],
});

// Clean up when done (important in SPAs)
handle.destroy();

Chart.js renderers

import { createPivotUI, pivotUtilities } from "@jmars25/pivottable-ts/vanilla";
import { chartjsRenderers } from "@jmars25/pivottable-ts/renderers/chartjs";

createPivotUI(el, data, {
  renderers: { ...pivotUtilities.renderers, ...chartjsRenderers },
  rendererName: "Bar Chart",
});

Available renderers: Bar Chart, Stacked Bar Chart, Horizontal Bar Chart, Line Chart, Area Chart, Scatter Chart, Multiple Pie Chart.


Locales

Import the side-effect module once at your app entry point to register all 15 locales, then pass locale to any create function:

import "@jmars25/pivottable-ts/locales"; // registers: cs, da, de, es, fr, it, ja, nl, pl, pt, ru, sq, tr, zh

createPivotUI(el, data, { locale: "de" });

Supported locales: cs da de es fr it ja nl pl pt ru sq tr zh (plus the default en).


React

import { useEffect, useRef, useMemo } from "react";
import { createPivotUI } from "@jmars25/pivottable-ts/vanilla";
import type { PivotUIOptions } from "@jmars25/pivottable-ts/vanilla";
import "@jmars25/pivottable-ts/dist/pivot.css";
import "@jmars25/pivottable-ts/locales";

function PivotTable({ data, locale = "en", ...opts }: { data: unknown[]; locale?: string } & PivotUIOptions) {
  const ref  = useRef<HTMLDivElement>(null);
  const stable = useMemo(() => opts, Object.values(opts)); // eslint-disable-line

  useEffect(() => {
    if (!ref.current) return;
    const handle = createPivotUI(ref.current, data, stable, true, locale);
    return () => handle.destroy();
  }, [locale]);

  return <div ref={ref} style={{ width: "100%" }} />;
}

See examples/react-demo/ for a full working example with locale switching and Chart.js renderers.


Vue

<script setup lang="ts">
import { ref, watch, onMounted, onUnmounted } from "vue";
import { createPivotUI } from "@jmars25/pivottable-ts/vanilla";
import "@jmars25/pivottable-ts/dist/pivot.css";
import "@jmars25/pivottable-ts/locales";

const props  = defineProps<{ data: unknown[]; locale?: string }>();
const el     = ref<HTMLElement | null>(null);
let   handle: ReturnType<typeof createPivotUI> | null = null;

function init() {
  if (!el.value) return;
  handle?.destroy();
  handle = createPivotUI(el.value, props.data, {}, true, props.locale ?? "en");
}

onMounted(init);
watch(() => props.locale, init);
onUnmounted(() => handle?.destroy());
</script>

<template>
  <div ref="el" style="width: 100%" />
</template>

See examples/vue-demo/ for a full working example.


Columnar input

For large datasets, pass data as typed arrays instead of an array of row objects. Strings are dictionary-encoded (Uint16Array), numbers use Float64Array. This avoids per-row object allocation and speeds up pivot computation significantly.

import { PivotData } from "@jmars25/pivottable-ts";
import type { ColumnarInput } from "@jmars25/pivottable-ts";

const input: ColumnarInput = {
  columnFormat: true,
  columnNames: ["Region", "Product", "Sales"],
  columns: {
    Region:  new Uint16Array([0, 1, 0, 1]),   // indices into dicts.Region
    Product: new Uint16Array([0, 0, 1, 1]),   // indices into dicts.Product
    Sales:   new Float64Array([120, 340, 80, 210]),
  },
  dicts: {
    Region:  ["North", "South"],
    Product: ["Widget", "Gadget"],
  },
};

createPivot(el, input, { rows: ["Region"], cols: ["Product"], vals: ["Sales"] });

Streaming input

PivotStream accepts records one at a time, accumulates them into columnar format internally, then hands off to PivotData when done. Useful for WebSockets, CSV parsing, or any source where data arrives incrementally.

import { PivotStream } from "@jmars25/pivottable-ts";

const stream = new PivotStream({
  onComplete: (_err, count, s) => {
    console.log(`Loaded ${count} rows`);
    createPivot(el, s.toColumnar(), { rows: ["Region"], cols: ["Product"], vals: ["Sales"] });
  },
});

// Push records as they arrive
stream.push({ Region: "North", Product: "Widget", Sales: 120 });
stream.push({ Region: "South", Product: "Gadget", Sales: 340 });
stream.done();

Fetch a CSV stream directly

await stream.fromFetch("/api/data.csv");
// onComplete fires automatically when the fetch finishes

CDN / script tag

No build step needed. SortableJS is bundled in — only two tags required:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jmars25/pivottable-ts/dist/pivot.css">
<script src="https://cdn.jsdelivr.net/npm/@jmars25/pivottable-ts/dist/pivot.min.js"></script>
<script>
  const { createPivotUI } = PivotTableTS;
  createPivotUI(document.getElementById("output"), data, {
    rows: ["Region"],
    cols: ["Product"],
  });
</script>

API reference

createPivot(container, data, opts?)

Renders a static (non-interactive) pivot table into container.

| Option | Type | Default | Description | |---|---|---|---| | rows | string[] | [] | Row attributes | | cols | string[] | [] | Column attributes | | vals | string[] | [] | Value attributes | | aggregator | function | count() | Aggregation function | | aggregatorName | string | "Count" | Display name for the aggregator | | renderer | function | table renderer | Output renderer | | filter | (record) => boolean | — | Exclude records | | sorters | Record / function | — | Custom sort order per attribute | | derivedAttributes | Record<string, fn> | — | Computed columns | | locale | string | "en" | UI locale |

createPivotUI(container, data, opts?, overwrite?, locale?)

Renders a drag-and-drop pivot UI. Returns a PivotUIHandle with a .destroy() method.

Additional options beyond createPivot:

| Option | Type | Description | |---|---|---| | renderers | Record<string, fn> | Map of renderer name → renderer function | | rendererName | string | Initially selected renderer | | hiddenAttributes | string[] | Attributes hidden from all lists | | hiddenFromAggregators | string[] | Hidden from the aggregator value picker | | hiddenFromDragDrop | string[] | Hidden from drag-and-drop but still usable | | inclusions / exclusions | Record<string, string[]> | Pre-filter attribute values | | onRefresh | (opts) => void | Called on every UI interaction |

pivotUtilities

Namespace re-exported from the vanilla adapter. Contains:

  • aggregatorTemplates — factory functions for building aggregators
  • aggregators — ready-to-use aggregator map
  • renderers — built-in table/heatmap renderers
  • numberFormat — number formatting helper
  • sortAs, naturalSort, getSort — sorting utilities

License

MIT — see LICENSE.md. © 2026 jmars25. Original pivottable © 2012 Nicolas Kruchten.