Getting started

The charts block is one component, <Charts />, that draws thirty-plus chart types selected by the type prop. Everything but the data itself is a flat, typed prop: verifiable by contract, reactive by construction.

Install

npm install @lemonadejs/charts@beta
import Charts from '@lemonadejs/charts';
import '@lemonadejs/charts/style.css';

The package has a single peer dependency: lemonadejs itself. No d3, no canvas polyfills, nothing else arrives with it.

Your first chart

live
import Charts from '@lemonadejs/charts';

const series = [
    { name: 'Revenue', data: [120, 190, 80, 220] },
    { name: 'Cost', data: [80, 105, 130, 140] },
];

const App = () => html`<${Charts} type="bar"
    categories="${['Q1', 'Q2', 'Q3', 'Q4']}"
    series="${series}" legend labels title="Quarterly results" />`;

The data definition

Two props carry all the data; everything else is presentation:

  • series: [{ name, data, color? }]. data is a plain array of numbers for most types; specialty types accept richer points ([x, y] pairs for scatter, { name, value } for pie/treemap/funnel, { from, to, value } for sankey/chord).
  • categories: the x-axis labels (bar/line), slice names (pie), or row/column labels (heatmap). Optional for types that carry names in their points.

The same pair drives every type, so switching from a bar to a line to a stacked area is a one-word change, and since type is a live prop, it can even happen at runtime.

Reactivity

Every declared prop arrives as a live state. Pass a plain value for a static chart, or pass a state for a live wire: assign to it and only the dependent parts of the scene rebuild:

live
import Charts from '@lemonadejs/charts';

const App = (props, { state }) => {
    const series = state([{ name: 'Sales', data: [12, 19, 8, 22] }]);
    const shuffle = () => {
        series.value = [{ name: 'Sales',
            data: series.value[0].data.map(() => Math.round(5 + Math.random() * 20)) }];
    };
    return html`<div>
        <button onclick="${shuffle}">Randomize</button>
        <${Charts} type="bar" categories="${['Q1', 'Q2', 'Q3', 'Q4']}"
            series="${series}" labels />
    </div>`;
};

Note the v6 contract: assignment triggers, mutation does not. Build a new array (or call .touch()) rather than pushing into the old one.

Three deployment forms

import { html, setComponents, createWebComponent } from 'lemonadejs';
import Charts from '@lemonadejs/charts';

html`<${Charts} />`            // by value, no registration needed
setComponents({ Charts });     // register once, then <Charts /> by name
createWebComponent(Charts);    // <lm-charts> for plain HTML or any framework

As a web component, attributes arrive as strings and are coerced to the declared prop types; set rich values (arrays, objects) via el.props = { series, categories }.

The contract

The machine-readable schema ships with the package, useful for tooling and for AI agents that generate charts:

import contract from '@lemonadejs/charts/contract.json';

verify.json in the package carries the conformance proof (111 checks) produced by verify(Charts). See Contracts for how the verification gate works.

Where next