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

@tabviz/core

v0.5.0

Published

Interactive forest plots and rich tables — JavaScript runtime for the tabviz R package

Downloads

2,194

Readme

@tabviz/core

JavaScript runtime + authoring API for tabviz — the publication-quality forest plots and rich interactive tables otherwise consumed via the tabviz R package.

Status: 0.2.0 — pre-1.0. Authoring API (function builders mirroring R's tabviz() / col_*() / viz_*() / theme_*()) landed; wire format stable at v1.0; subpath shape stable. See docs/dev/r-ts-parity-notes.md for per-helper R↔TS parity status and known gaps.

Quick start — build a spec, mount it

import {
  tabviz, createTabviz,
  colText, colInterval, vizForest,
} from "@tabviz/core";
import "@tabviz/core/style.css";

const spec = tabviz({
  data: rows,
  label: "study",
  theme: "lancet",
  columns: [
    colText({ field: "study", header: "Study" }),
    colInterval({ point: "hr", lower: "lcl", upper: "ucl" }),
    vizForest({ point: "hr", lower: "lcl", upper: "ucl", scale: "log" }),
  ],
  title: "Hazard ratios across studies",
});

const instance = createTabviz(document.querySelector("#plot")!, spec);

tabviz() returns a WebSpec (the wire-format payload). createTabviz mounts it. Every R helper has a TS mirror — argument names + defaults match; snake_case in R → camelCase in TS.

What this package will publish

@tabviz/core exposes five subpaths over a single versioned npm package — one repo, one version, one source of truth.

| Subpath | What it exports | Who reaches for it | |---|---|---| | @tabviz/core | createTabviz, createSplitTabviz factories + wire-format types | Web-app consumers wanting visual parity with R-rendered tabvizes; vanilla TS/JS in any framework | | @tabviz/core/svelte | ForestPlot, SplitForestPlot components, createForestStore factories | Svelte consumers composing the components directly | | @tabviz/core/export | exportToSVG, exportToPNG, computeNaturalDimensions | Headless rendering pipelines (V8, node-rsvg, server-side export) | | @tabviz/core/spec | TypeScript types + JSON Schema (v1.0.json) | Consumers validating wire payloads | | @tabviz/core/htmlwidgets | R-side htmlwidgets adapters | The R package's vendored build artifacts (not for direct npm use) |

Installation

npm install @tabviz/core svelte

Svelte is the underlying component runtime. You don't write Svelte code — createTabviz returns a plain imperative handle — but the main entry and the /svelte subpath both need Svelte 5 installed as a peer. The /export and /spec subpaths are framework-free and work without it.

Quick start (preview)

import { createTabviz } from "@tabviz/core";
import "@tabviz/core/style.css";

const instance = createTabviz(document.querySelector("#plot")!, spec, {
  width: 800,
  height: 600,
});

instance.on("selected", (rowIds) => console.log("selection:", rowIds));
instance.sortBy({ column: "estimate", direction: "asc" });

Spec shape is defined in @tabviz/core/spec; you can validate against the JSON Schema (one schema file per minor version — currently v1.0.json).

Wire-format versioning

Every WebSpec carries an explicit version field. The runtime validates it on every render. See docs/dev/versioning.md for the SemVer policy and minor-evolution rules.

Consuming from non-Svelte frameworks

The createTabviz factory returns a typed TabvizInstance with update, sortBy, applyFilter, selectRows, setSemantic, setTheme, setZoom, setAspectRatio, on (typed event subscriptions), destroy. Internally it mounts the Svelte components into the host element; from the React / Vue / Solid side you treat the host element + instance handle as an opaque imperative widget. You still install Svelte as a peer dep (the runtime is bundled-less so the consumer's app and @tabviz/core share the same Svelte instance).

Source layout

| Path | Purpose | |---|---| | src/core/ | Framework-agnostic factories (createTabviz, createSplitTabviz) | | src/svelte/ | Top-level Svelte components published as /svelte | | src/export/ | Pure-function SVG/PNG generators + V8 shim | | src/spec/ | TypeScript types + JSON Schema per minor | | src/htmlwidgets/ | R-side htmlwidgets adapters (Shiny proxy, message channels) | | src/stores/ | Svelte 5 reactive stores | | src/lib/ | Cross-cutting utilities (formatters, scales, banding, etc.) | | src/components/ | Internal sub-components (controls, viz, table cells) |

The lib/ and components/ trees are implementation details bundled into the published chunks; they're not part of the public subpath surface.

Building

Four build paths produce four artifact sets:

npm run build           # the three R-side IIFE bundles
npm run build:widget    # inst/htmlwidgets/tabviz.js
npm run build:split     # inst/htmlwidgets/tabviz_split.js
npm run build:v8        # inst/js/svg-generator.js
npm run build:npm       # dist/ ESM bundles + style.css + .d.ts types

R-side bundles ship vendored inside inst/ for htmlwidgets consumers. The npm path emits per-subpath ESM into dist/:

dist/
├── index.mjs          # @tabviz/core entry
├── svelte.mjs         # @tabviz/core/svelte entry
├── export.mjs         # @tabviz/core/export entry
├── spec.mjs           # @tabviz/core/spec entry
├── style.css          # standalone CSS for npm consumers
├── chunks/            # shared chunks
├── core/, svelte/, export/, spec/, …   # emitted .d.ts trees

build:npm runs vite, then tsc --emitDeclarationOnly, then a small postprocessor (scripts/rewrite-dts-aliases.mjs) that rewrites the internal $lib/$stores/$types/… aliases in the published .d.ts files to relative paths so npm consumers don't need our tsconfig.paths.

CI gates

Two scripts gate publish-readiness:

npm run check:size       # fails on any bundle >10% over budget
npm run check:lockfiles  # validates package-lock.json + bun.lock both sync with package.json

The size budget lives in bundle-size-budget.json (raw bytes, intentional growth is bumped in the same PR with justification).

Toolchain

The build artifact ships from npm (npm ci in CI, package-lock.json is canonical). Local development with bun is supported and tracked — bun.lock is checked in so bun install + bun test work fast, but the published artifact is built from package-lock.json. The two lockfiles must agree on resolved versions; npm run check:lockfiles gates this in CI.

Testing

npm test               # bun + vitest
npm run test:bun       # bun only — pure-TS tests
npm run test:vitest    # vitest — Svelte-runes tests (.runes.ts)

Bun runs the bulk of fast pure-TS tests. Vitest runs tests that need the Svelte 5 runes compiler — those live under *.runes.ts so bun's default *.{test,spec}.ts glob skips them.

Related