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.
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
| name | value | picture |
|---|---|---|
| Apples | 12 | |
| Kiwis | 22 | |
| Lemons | 7 |
A row per thing, a column per value.
The one slat you describe
<Label>d.name<img>d.picture<Bar><Label>d.valueBuild once, from blocks: a Label, a picture, a Bar and a Label.
The chart rhp draws
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:
| Block | What it draws |
|---|---|
Bar | a bar from one value to another |
Dot | a point at a value |
Tick | a short line across the slat, at a value |
Label | text at a value, or beside the chart |
Cell | a colored cell, for heatmaps |
Place | nothing: a spot at a value, for an element of your own |
Area | a smooth shape, for how values spread |
Line | a 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 (
Fruitin 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 asd.fruitandd.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.