Skip to content

What is rhp?

rhp (reactive html plots) is a free, open-source SolidJS library that turns tabular data into interactive, infographic-style charts.

Unlike other libraries, it combines HTML elements, CSS, and JavaScript to create the visualizations. A bar is a div in your page, not a shape drawn into an SVG or a canvas. This means you are able to take advantage of tools that the browser already provides and is optimized for. It also opens up possibilities that are tricky or difficult for a chart drawn into an SVG or a canvas: a photo cropped inside a bar, a button in a label, a chart nested inside another one. It also allows you to make things as interactive as you want.

Drag the slider, then look at the code under the chart: that’s all it takes.

Apples
12
Bananas
18
Cherries
7
Kiwis
22
import { createSignal } from "solid-js";
import { Chart, Plot, Bar, Label, slat, sortBy } from "@bezda/rhp";

// One slat of the chart: a name, a bar and a number.
const Fruit = slat(
  {
    css: `
      .bar { --rhp-end-radius: 6px; }
      .value { font-weight: 700; }
    `,
  },
  (d) => (
    <div>
      <Label edge="start">{d.fruit}</Label>
      <Bar to={d.sold} class="bar" />
      <Label at={d.sold} class="value">
        {d.sold}
      </Label>
    </div>
  ),
);

export default function FruitSold() {
  const [apples, setApples] = createSignal(12);
  return (
    <>
      <label class="demo-controls">
        Apples sold
        <input
          type="range"
          min="0"
          max="30"
          value={apples()}
          onInput={(e) => setApples(+e.target.value)}
        />
      </label>
      <Chart scale={[0, 30]}>
        <Plot
          fruit={["Apples", "Bananas", "Cherries", "Kiwis"]}
          sold={[apples(), 18, 7, 22]}
          order={sortBy("sold", "desc")}
        >
          {Fruit}
        </Plot>
      </Chart>
    </>
  );
}

How it works

A chart in rhp is a stack of slats, one for each row of your data. A slat holds everything that represents that row: a name, a value, maybe a picture. You describe one slat, and rhp takes care of the rest.

Your data

namevaluepicture
Apples12
Kiwis22
Lemons7

A row per thing, a column per value.

The one slat you describe

<Label>d.name<img>d.picture<Bar>d.value<Label>d.value

Build once, from blocks: a Label, a picture, a Bar and a Label.

The chart rhp draws

Apples12
Kiwis22
Lemons7

One slat per row, filled with its values.

It is called a “slat” rather than a “row” because it can have any orientation and isn’t necessarily horizontal like a row would be. The key idea is that charts are constructed by stacking, piling, or arranging these slats in some organized fashion. You build a slat from a few blocks, and rhp puts each block in its correct place on the chart:

BlockWhat it draws
Bara bar from one value to another
Dota point at a value
Ticka short line across the slat, at a value
Labeltext at a value, or beside the chart
Cella colored cell, for heatmaps
Placenothing: a spot at a value, for an element of your own
Areaa smooth shape, for how values spread
Linea line through points: a sparkline, or a line chart

When your numbers change, the chart follows by itself. Only what changed moves: the bar that grew, and the slats that swap places.

Why it’s built this way

Look at the code under the chart above: it has two parts, and each has one job.

  • The slat designs, the Chart assembles. The slat (Fruit in the code above) is a template for one row of data: which blocks it holds and how they look. The Chart and its Plot put the slats together: they layer and stack them, and pass to each one the data it needs. Change the design and every slat follows; change the data and the design stays as it is.
  • You write a slat once, not once per bar. There are no loops to write, no code for each bar, and no copies to keep in step. A fix to the slat reaches every slat drawn from it, in every chart that uses it.
  • Blocks, not chart types. Instead of a catalog of chart types, each with its own options, rhp has eight blocks you combine. A bar chart, a box plot and a timeline are the same few blocks arranged differently, so a chart nobody planned for needs nothing new.
  • Data goes in as columns. Each prop of a Plot is one column of your table (fruit, sold), and each slat gets its row’s values as d.fruit and d.sold. A table from a spreadsheet or an API maps straight onto the chart.
  • Logic and markup stay apart. A chart is a component: its state, sorting and event handlers live in the function, and its JSX only says what is drawn.
  • Styles sit together. A slat’s CSS lives beside it, or in a file of its own, as in the gallery’s examples. You can restyle a chart without touching its data or its logic.

Why rhp

  • A chart is elements, not a drawing. You style it the way you style the rest of your page: classes, hover states, gradients, images and fonts. A bar is an element you can inspect in the browser, not a shape inside an SVG or a canvas.
  • It’s small. A bar chart adds 18 kB gzipped, or 25 kB together with Solid, the library it’s built on.
  • It’s quick. Changing a number changes one CSS variable on one element, so charts stay smooth while you drag, type, or stream in data.
  • Charts don’t break each other. A slat’s styles only reach its own slats, and the page’s CSS can’t bend a chart out of shape.
  • One chart, two directions. The same code draws horizontal and vertical charts.

What you need to know

rhp is built on SolidJS, a small library for building web pages. You don’t need to know Solid to start: the examples in these pages show all you need. If you know React, Solid’s JSX will look familiar.

No build tools? rhp also works in a plain HTML page, loaded from a CDN.

Next: install rhp, or jump straight into your first chart.