Blocks
A slat is made of blocks. You give a block numbers from your data, and rhp works out where on the chart those numbers fall. You can put as many blocks in a slat as you like, and any elements of your own around or inside them. For many scatter points, ManyDots draws a collection directly inside a Chart.
Bar
A bar from from to to.
from is 0 if you leave it out.
thick sets how thick the bar is: a length like "10px", or a fraction of the slat’s thickness, like 0.5 for half of it.
import { Chart, Plot, Bar, Label } from "@bezda/rhp";
// Opening hours: each bar runs from opening to closing time.
export default function Hours() {
return (
<Chart
scale={[6, 24]}
ticks={[6, 9, 12, 15, 18, 21, 24]}
format={(h) => h + ":00"}
>
<Plot
shop={["Bakery", "Library", "Gym"]}
opens={[7, 10, 6]}
closes={[14, 19, 23]}
>
{(d) => (
<div>
<Label edge="start">{d.shop}</Label>
<Bar from={d.opens} to={d.closes} thick="10px" />
</div>
)}
</Plot>
</Chart>
);
}A Bar whose to is below its from runs backward, like a negative value.
Dot
A round point at at.
size sets its diameter (10px by default).
import { Chart, Plot, Dot, Label } from "@bezda/rhp";
// Race times: a dot for each runner's best lap.
export default function Laps() {
return (
<Chart scale={[60, 80]} format={(s) => s + " s"}>
<Plot
runner={["Ana", "Ben", "Chloe", "Dev"]}
best={[71.2, 66.8, 64.5, 69.9]}
>
{(d) => (
<div>
<Label edge="start">{d.runner}</Label>
<Dot at={d.best} size="14px" />
</div>
)}
</Plot>
</Chart>
);
}ManyDots
A bulk collection of plain HTML points, positioned by at and cross on the Chart’s two scales.
Use ManyDots directly inside the Chart, without a Plot or a slat per point.
Choose it explicitly for a large scatter collection; Dot remains available at any point count for individual blocks and custom slat content.
Points can share styling, use category classes, or have individual colors, sizes, shapes, and styles. The collection uses light DOM, so document queries and native event delegation can reach its points.
See the ManyDots page for the live example, complete props, interaction patterns, and current source-build availability.
Tick
A short line across the slat at at: a goal, a median, a threshold.
import { Chart, Plot, Bar, Tick, Label } from "@bezda/rhp";
// Steps against a daily goal: the bar is the steps, the tick the goal.
export default function Steps() {
return (
<Chart scale={[0, 12]} format={(k) => k + "k"}>
<Plot
day={["Mon", "Tue", "Wed"]}
steps={[8.2, 11.5, 5.1]}
goal={[10, 10, 8]}
>
{(d) => (
<div>
<Label edge="start">{d.day}</Label>
<Bar to={d.steps} />
<Tick at={d.goal} color="ink" />
</div>
)}
</Plot>
</Chart>
);
}Label
Text on the chart.
at={value}puts it just past that value. Addside="before"to put it just before instead, which suits negative bars.edge="start"puts it before the chart, where names go.edge="end"puts it after.
import { Chart, Plot, Bar, Label } from "@bezda/rhp";
// Profit and loss: the number sits just past the bar's end.
export default function Profit() {
return (
<Chart scale={[-40, 40]} ticks={[-40, -20, 0, 20, 40]}>
<Plot
month={["Jan", "Feb", "Mar", "Apr"]}
profit={[25, -12, 8, -30]}
>
{(d) => (
<div>
<Label edge="start">{d.month}</Label>
<Bar
to={d.profit}
color={d.profit < 0 ? "negative" : "positive"}
/>
<Label
at={d.profit}
side={d.profit < 0 ? "before" : undefined}
>
{d.profit}
</Label>
</div>
)}
</Plot>
</Chart>
);
}Cell
A cell that fills the space it is given, colored by its value: the chart’s scale runs from the theme’s low color to its high one.
Cells make heatmaps.
Here each day’s slat holds a small Plot of its own, one cell per hour (more about this in charts inside slats).
import { Chart, Plot, Cell, Label } from "@bezda/rhp";
// Visitors per hour: a slat per day, a cell per hour.
const visitors = [
[2, 8, 21, 35, 30, 12],
[4, 11, 26, 40, 34, 15],
[9, 24, 38, 29, 18, 6],
];
export default function Visitors() {
return (
<Chart scale={[0, 40]} ticks={false}>
<Plot day={["Fri", "Sat", "Sun"]} hours={visitors}>
{(d) => (
<div>
<Label edge="start">{d.day}</Label>
<Plot orientation="across" count={d.hours}>
{(h) => (
<div>
<Cell value={h.count} title={h.count + " visitors"} />
</div>
)}
</Plot>
</div>
)}
</Plot>
</Chart>
);
}Place
A Place draws nothing at all: no size, no colour, nothing on the screen.
It only marks a spot, so whatever you put inside it sits at at on the scale.
Use it for the pieces that are yours to draw, a badge, a bubble, a photo, a needle, where rhp only has to say where they go.
import { Chart, Plot, Bar, Label, Place, slat } from "@bezda/rhp";
// A Place draws nothing: the badge inside it sits at the value.
const Climb = slat(
{
thickness: 44,
room: { start: 70, end: 30 },
css: `
.badge {
position: absolute;
translate: -50% -50%;
padding: 2px 7px;
border-radius: 99px;
background: var(--rhp-ink);
color: var(--rhp-surface);
font-size: 11px;
font-weight: 700;
white-space: nowrap;
}
`,
},
(d) => (
<div>
<Label edge="start">{d.peak}</Label>
<Bar to={d.metres} />
<Place at={d.metres}>
<span class="badge">{d.metres} m</span>
</Place>
</div>
),
);
export default function Peaks() {
return (
<Chart scale={[0, 9000]} ticks={[0, 3000, 6000, 9000]}>
<Plot
peak={["Everest", "K2", "Denali", "Mont Blanc"]}
metres={[8849, 8611, 6190, 4808]}
>
{Climb}
</Plot>
</Chart>
);
}acrossputs it across the band, from 0 to 1, andcrossputs it on a second axis instead.- Everything inside it is yours: rhp adds no padding, no background and no text rules to undo.
- Without it you would borrow another block and switch its appearance off, which is CSS you would have to keep in step with rhp.
Area
A smooth shape over the scale, from a list of points, each [value, height].
The tallest point reaches the full thickness of the slat.
Add mirror to draw it both ways from the middle, for violin plots.
Add smooth to join the points with curves instead of straight lines.
import { Chart, Plot, Area, Label } from "@bezda/rhp";
// When people arrive at a café: one smooth shape per day.
export default function Arrivals() {
return (
<Chart scale={[7, 19]} format={(h) => h + ":00"}>
<Plot
day={["Weekday", "Weekend"]}
shape={[
[
[7, 1],
[8, 6],
[9, 4],
[12, 7],
[13, 5],
[17, 3],
[19, 1],
],
[
[7, 0],
[9, 2],
[11, 6],
[13, 8],
[15, 5],
[17, 2],
[19, 1],
],
]}
>
{(d) => (
<div>
<Label edge="start">{d.day}</Label>
<Area points={d.shape} />
</div>
)}
</Plot>
</Chart>
);
}For a shape made from raw samples, the density helper computes the points for you.
Line
A line through a list of points, each [value, y].
In a slat it is a sparkline.
The largest y reaches the top of the slat, so each slat is scaled on its own.
Set peak to the y that should reach the top, and then the slats can be compared with each other.
Add fill to fill under the line, and smooth to join the points with curves.
import { Chart, Plot, Line, Label } from "@bezda/rhp";
// Visits to three pages: a sparkline per slat, with one peak for all so they compare.
export default function Visits() {
return (
<Chart
scale={[1, 7]}
ticks={[1, 2, 3, 4, 5, 6, 7]}
format={(day) => "MTWTFSS"[day - 1]}
>
<Plot
page={["Home", "Pricing", "Docs"]}
visits={[
[320, 280, 350, 300, 390, 180, 150],
[90, 120, 110, 160, 150, 60, 40],
[210, 240, 260, 230, 250, 120, 140],
]}
>
{(d) => (
<div>
<Label edge="start">{d.page}</Label>
<Line points={d.visits.map((v, i) => [i + 1, v])} peak={400} fill />
</div>
)}
</Plot>
</Chart>
);
}On a chart with a second axis, y is on that axis instead: a line chart.
What every block takes
Every block also takes what an HTML element takes:
classandstyleto style it,color: a theme color ("series-2","positive") or any CSS color,- event handlers such as
onClick, and attributes such astitle,data-*andaria-*, - children: text, an image, or any other element, drawn inside the block.
Bar, Dot, Tick, Label and Cell also take shape, an outline to draw instead of their rectangle.
shape() makes one from SVG’s path commands, in the block’s own box:
import { shape } from "@bezda/rhp";
// a bar with a pointed end: 26px back from its end, it narrows to a point at the end's middle
const arrow = shape(["M", 0, 0], ["L", "-26px", 0], ["L", 1, 0.5], ["L", "-26px", 1], ["L", 0, 1], ["Z"]);
<Bar to={d.value} shape={arrow} />
The first number of each point runs along the scale, from the block’s start (0) to its end (1), and the second across the band, from 0 to 1.
A length such as "26px" is measured from the start, and "-26px" from the end.
rhp turns the shape for a vertical chart and for a bar that runs backward, so you write it once.
The full list of props is in the blocks reference.