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

@internetstiftelsen/charts

v0.0.8

Published

A framework-agnostic, composable charting library built on D3.js with TypeScript.

Readme

Chart Library

A framework-agnostic, composable charting library built on D3.js with TypeScript.

Features

  • Framework Agnostic: Core library has zero framework dependencies - works with vanilla JS, React, Vue, Svelte, or any other framework
  • Flexible Scale System: Support for band, linear, time, and logarithmic scales
  • Composable Architecture: Build charts by composing components (lines, axes, grids, tooltips, legends, titles)
  • Layout-Driven Design: Components self-measure and automatically adjust chart dimensions
  • Automatic Resize: Built-in ResizeObserver handles responsive behavior automatically
  • Type Safe: Written in TypeScript with comprehensive type definitions
  • Data Validation: Built-in validation with helpful error messages
  • Performance Optimized: Data caching and minimized redundant calculations
  • Automatic Color Assignment: Smart color palette system with sensible defaults

Installation

npm install @internetstiftelsen/charts

Quick Start

Vanilla JavaScript

import { XYChart } from '@internetstiftelsen/charts/xy-chart';
import { Line } from '@internetstiftelsen/charts/line';
import { Bar } from '@internetstiftelsen/charts/bar';
import { XAxis } from '@internetstiftelsen/charts/x-axis';
import { YAxis } from '@internetstiftelsen/charts/y-axis';
import { Grid } from '@internetstiftelsen/charts/grid';
import { Tooltip } from '@internetstiftelsen/charts/tooltip';
import { Legend } from '@internetstiftelsen/charts/legend';

// Your data
const data = [
    { date: '2010', revenue: 100, expenses: 80 },
    { date: '2011', revenue: 150, expenses: 90 },
    { date: '2012', revenue: 200, expenses: 110 },
    { date: '2013', revenue: 250, expenses: 130 },
];

// Create chart
const chart = new XYChart({ data });

// Add components
chart
    .addChild(new Title({ text: 'Revenue vs Expenses' }))
    .addChild(new Grid({ horizontal: true, vertical: false }))
    .addChild(new XAxis({ dataKey: 'date' }))
    .addChild(new YAxis())
    .addChild(
        new Tooltip({
            formatter: (dataKey, value) => `<strong>${dataKey}</strong>: $${value}k`,
        })
    )
    .addChild(new Legend({ position: 'bottom' }))
    .addChild(new Line({ dataKey: 'revenue' }))  // Auto-assigned color
    .addChild(new Line({ dataKey: 'expenses' })); // Auto-assigned color

// Render to DOM (automatically resizes with container)
chart.render('#chart-container');

// Later: update with new data
chart.update(newData);

// Clean up when done
chart.destroy();

With React (Demo Wrapper)

import { useRef, useEffect } from 'react';
import { XYChart, Line, Bar, XAxis, YAxis, Grid, Tooltip, Legend } from './charts';

function Chart({ data }) {
    const containerRef = useRef(null);
    const chartRef = useRef(null);

    useEffect(() => {
        if (containerRef.current) {
            // Create chart
            const chart = new XYChart({ data });

            chart
                .addChild(new Grid({ horizontal: true }))
                .addChild(new XAxis({ dataKey: 'column' }))
                .addChild(new YAxis())
                .addChild(new Tooltip())
                .addChild(new Legend({ position: 'bottom' }))
                .addChild(new Line({ dataKey: 'value1' }))
                .addChild(new Line({ dataKey: 'value2' }));

            chart.render(containerRef.current);
            chartRef.current = chart;

            return () => {
                chart.destroy();
            };
        }
    }, []);

    // Update when data changes
    useEffect(() => {
        if (chartRef.current && data) {
            chartRef.current.update(data);
        }
    }, [data]);

    return <div ref={containerRef} />;
}

API Reference

XYChart

The main chart class for creating XY-coordinate charts (line, bar, or mixed).

Constructor

new XYChart(config: XYChartConfig)

Config Options:

  • data: DataItem[] - Array of data objects (required)
  • theme?: Partial<ChartTheme> - Theme customization
    • width: number - Chart max-width in pixels (default: 928)
    • height: number - Chart height in pixels (default: 600)
    • margins: { top, right, bottom, left } - Base margins around plot area (default: { top: 20, right: 20, bottom: 30, left: 40 })
    • colorPalette: string[] - Array of colors for auto-assignment
    • gridColor: string - Grid line color (default: '#e0e0e0')
    • axis: { fontFamily, fontSize } - Axis text styling
  • scales?: AxisScaleConfig - Scale configuration
    • x?: { type: 'band' | 'linear' | 'time' | 'log', domain?: any[], padding?: number, nice?: boolean }
    • y?: { type: 'band' | 'linear' | 'time' | 'log', domain?: any[], padding?: number, nice?: boolean }

Methods

addChild(component: ChartComponent): this Adds a component to the chart (chainable).

render(target: string): HTMLElement Renders the chart to a DOM element specified by CSS selector. Automatically sets up resize handling.

update(data: DataItem[]): void Updates the chart with new data and re-renders.

destroy(): void Cleans up all resources, removes resize observer, and clears the chart from the DOM.

Components

Line

Renders a line series on the chart.

new Line({
    dataKey: string,          // Key in data objects for Y values (required)
    stroke? : string,          // Line color (auto-assigned if omitted)
    strokeWidth? : number,     // Line width in pixels (default: 2)
})

Bar

Renders a bar series on the chart.

new Bar({
    dataKey: string,          // Key in data objects for Y values (required)
    fill? : string,            // Bar color (auto-assigned if omitted)
})

XAxis

Renders the X axis.

new XAxis({
    dataKey? : string,  // Key in data objects for X values (auto-detected if omitted)
})

YAxis

Renders the Y axis.

new YAxis({
    tickFormat?: string | null,  // D3 format specifier (e.g., 's' for SI-prefix like "35k"). Default: null (no formatting)
})

Examples:

new YAxis()                         // Shows raw numbers: 35000
new YAxis({ tickFormat: 's' })      // Shows SI-prefix: 35k
new YAxis({ tickFormat: '$,' })     // Shows formatted: $35,000

Grid

Renders grid lines.

new Grid({
    horizontal? : boolean,  // Show horizontal lines (default: true)
    vertical? : boolean,    // Show vertical lines (default: true)
})

Tooltip

Renders interactive tooltips on hover.

new Tooltip({
    formatter? : (dataKey: string, value: any, data: DataItem) => string
})

Example formatter:

new Tooltip({
    formatter: (dataKey, value, data) =>
        `<strong>${dataKey}</strong><br/>Value: ${value}<br/>Date: ${data.date}`
})

Legend

Renders a legend for the chart.

new Legend({
    position?: 'bottom',      // Position (currently only 'bottom' supported)
    marginTop?: number,       // Space above legend (default: 20)
    marginBottom?: number,    // Space below legend (default: 10)
})

Title

Renders a title for the chart.

new Title({
    text: string,             // Title text (required)
    fontSize?: number,        // Font size in pixels (default: 18)
    fontWeight?: string,      // Font weight (default: 'bold')
    align?: 'left' | 'center' | 'right',  // Alignment (default: 'center')
    marginTop?: number,       // Space above title (default: 10)
    marginBottom?: number,    // Space below title (default: 15)
})

Advanced Usage

Custom Scale Types

Use time scales for temporal data:

const chart = new XYChart({
    data: [
        { date: new Date('2024-01-01'), value: 100 },
        { date: new Date('2024-01-02'), value: 150 },
    ],
    scales: {
        x: { type: 'time', nice: true },
        y: { type: 'linear', nice: true },
    },
});

Use logarithmic scales for exponential data:

const chart = new XYChart({
    data: [
        { x: 1, y: 10 },
        { x: 2, y: 100 },
        { x: 3, y: 1000 },
    ],
    scales: {
        y: { type: 'log', domain: [1, 10000] },
    },
});

Custom Theming

const chart = new XYChart({
    data,
    theme: {
        width: 1200,           // Max-width (chart won't exceed this)
        height: 600,
        margins: {
            top: 30,
            right: 30,
            bottom: 40,
            left: 60,
        },
        colorPalette: ['#ff6b6b', '#4ecdc4', '#45b7d1', '#f7b731'],
        gridColor: '#333333',
        axis: {
            fontFamily: 'Inter, sans-serif',
            fontSize: '12',
        },
    },
});

Manual Color Assignment

chart
    .addChild(new Line({ dataKey: 'revenue', stroke: '#00ff00' }))
    .addChild(new Line({ dataKey: 'expenses', stroke: '#ff0000' }));

Responsive Charts

Charts automatically resize with their container using ResizeObserver. The chart width adapts to the container up to the theme.width (which acts as max-width).

// Container width: 500px → Chart width: 500px
// Container width: 1200px → Chart width: 928px (theme default max-width)

// Custom max-width
const chart = new XYChart({
    data,
    theme: { width: 1200 },  // Chart won't exceed 1200px
});

No manual resize calls needed - the chart automatically responds to container size changes!

Data Validation

The library includes built-in validation with helpful error messages:

// Empty data
new XYChart({ data: [] });
// Error: Data array cannot be empty

// Missing dataKey
new Line({ dataKey: 'nonexistent' });
// Error: Line: dataKey "nonexistent" not found in data items at indices: 0, 1, 2

// Invalid numeric data
new Line({ dataKey: 'textField' });
// Error: Line: No valid numeric values found for dataKey "textField"

Browser Support

Modern browsers with ES6+ support. Uses D3.js v7.

TypeScript

Full TypeScript support included:

import type { DataItem, ChartTheme, LineConfig } from './charts/types';

const data: DataItem[] = [
    { x: 1, y: 100 },
    { x: 2, y: 200 },
];

const config: LineConfig = {
    dataKey: 'y',
    stroke: '#8884d8',
    strokeWidth: 2,
};

Architecture

The library follows a composable, layout-driven design:

  • BaseChart: Abstract base class providing common functionality (lifecycle, rendering, validation)
  • XYChart: Concrete implementation for XY-coordinate charts (lines, bars, or mixed)
  • LayoutManager: Calculates component positions and plot area dimensions (D3 margin convention)
  • LayoutAwareComponent: Interface for self-measuring components (Title, Legend, Axes)
  • Components: Modular components that implement ChartComponent or LayoutAwareComponent
  • Validation: Centralized validation layer with ChartValidator
  • Scales: Flexible scale factory supporting multiple D3 scale types

Key principles:

  • Layout-driven: Components report their space requirements, plot area adjusts automatically
  • Separation of concerns: Only the plot area (grid) scales; UI elements stay fixed size
  • D3 conventions: Follows D3's margin convention pattern for clean, predictable layouts

This architecture makes it easy to add new chart types or series (Area, Scatter, etc.) by extending BaseChart or implementing new series components.

Performance

  • Data Caching: Sorted data is cached to avoid redundant sorting operations
  • Smart Re-rendering: Only re-renders when necessary (data updates or container resize)
  • Automatic Cleanup: ResizeObserver and tooltips properly cleaned up on destroy
  • Minimal DOM Manipulation: Uses D3's efficient data binding
  • SVG Optimization: Clean SVG generation with proper cleanup
  • Small Bundle: ~105 KB gzipped (including D3)
  • Small Bundle: ~105 KB gzipped (including D3)