Styling
You style a chart with plain CSS, written next to the slat it styles.
CSS for a slat
Wrap the slat function in slat() and give it css.
Put classes on the slat’s root and its blocks, and style those classes.
import { Chart, Plot, Bar, Label, slat } from "@bezda/rhp";
const Planet = slat(
{
thickness: 44,
css: `
.slat:hover {
background: color-mix(in srgb, var(--rhp-ink) 8%, transparent);
border-radius: 10px;
}
.name { font-size: 14px; font-weight: 600; }
.bar {
--rhp-start-radius: 0px;
--rhp-end-radius: 12px;
background: linear-gradient(
var(--rhp-toward-end),
var(--rhp-series-1),
var(--rhp-series-5)
);
}
.value {
font-size: 16px;
font-weight: 800;
--rhp-label-gap: 10px;
}
`,
},
(d) => (
<div class="slat">
<Label edge="start" class="name">
{d.planet}
</Label>
<Bar to={d.moons} class="bar" />
<Label at={d.moons} class="value">
{d.moons}
</Label>
</div>
),
);
export default function Moons() {
return (
<Chart scale={[0, 150]}>
<Plot
planet={["Jupiter", "Saturn", "Uranus", "Neptune"]}
moons={[95, 146, 28, 16]}
>
{Planet}
</Plot>
</Chart>
);
}That CSS only reaches this chart’s slats.
It can’t leak into your page or into other charts, so you can use short class names like .slat or .value without worrying.
It works in both directions: your page’s CSS can’t reach into a chart either.
Anything CSS can do to an element, it can do here, because a block and a slat are ordinary elements. A gradient on a bar, a web font on a label, an image behind a cell: all of it behaves the way it does anywhere else on your page.
Using someone else’s look
A slat’s CSS can be a list, which is joined in order:
import { NIGHT } from "./looks.js";
const Row = slat({ ...NIGHT, css: [NIGHT.css, own] }, (d) => …);
So a look is an ordinary object you can export, import, publish or paste: its CSS, and the layout that goes with it (thickness, inset, room).
Use it as it comes with slat(NIGHT, (d) => …), or put your own CSS after it, where it wins.
For a look to land on a chart it wasn’t written for, it has to aim at something both charts have. Class names are no good for that, because each chart picks its own. What every chart does have is what rhp writes on each block:
| Selector | What it reaches |
|---|---|
.rhp-bar, .rhp-dot, .rhp-tick, .rhp-cell, .rhp-area, .rhp-line | every block of that kind |
.rhp-label[data-rhp-edge="start"] | the name beside a slat, in the gutter |
.rhp-label[data-rhp-edge="end"] | a label in the gutter after the slat |
.rhp-label[data-rhp-at] | a label at a value on the scale |
.rhp-plot[data-rhp-overlap] | a Plot whose slats share one space |
Here one look is used by two slats built from different blocks, a plain bar and a bar with a dot at each end, and neither one needed a line of CSS of its own:
import { Chart, Plot, Bar, Dot, Label, slat } from "@bezda/rhp";
// One look for both slats, aimed at what rhp writes rather than at class names.
const NIGHT = {
thickness: 38,
room: { start: 76, end: 46 },
css: `
.rhp-label[data-rhp-edge="start"] { font-weight: 600; }
.rhp-bar, .rhp-dot { --rhp-radius: 99px; }
.rhp-label[data-rhp-at] {
font-weight: 700;
font-variant-numeric: tabular-nums;
color: var(--rhp-muted);
}
`,
};
const Warm = slat(NIGHT, (d) => (
<div>
<Label edge="start">{d.city}</Label>
<Bar to={d.high} />
<Label at={d.high}>{d.high}°</Label>
</div>
));
const Range = slat(NIGHT, (d) => (
<div>
<Label edge="start">{d.city}</Label>
<Bar from={d.low} to={d.high} thick="6px" />
<Dot at={d.low} size="13px" />
<Dot at={d.high} size="13px" />
<Label at={d.high}>{d.high}°</Label>
</div>
));
const CITIES = ["Oslo", "Madrid", "Cairo"];
const LOW = [-4, 3, 9];
const HIGH = [4, 12, 19];
export default function OneLook() {
return (
<>
<Chart scale={[-10, 30]} ticks={[-10, 0, 10, 20, 30]} format={(v) => v + "°"}>
<Plot city={CITIES} high={HIGH}>{Warm}</Plot>
</Chart>
<Chart scale={[-10, 30]} ticks={[-10, 0, 10, 20, 30]} format={(v) => v + "°"}>
<Plot city={CITIES} low={LOW} high={HIGH}>{Range}</Plot>
</Chart>
</>
);
}A look aims at what every chart has. What is particular to one chart, which of its two bars is the track and which is the progress, stays in that chart’s own CSS, where the person who built it can see it.
The variables rhp reads
A few CSS variables change how rhp draws a block. Their names follow the chart’s scale rather than the screen, saying start and end instead of left and right, so the same rule works whether the chart is horizontal or vertical.
| Variable | What it does |
|---|---|
--rhp-radius | rounds a Bar’s corners, one length (2px by default). For different corners, use the next two or plain border-radius. |
--rhp-start-radius, --rhp-end-radius | round one end of a Bar. The end is where its value is; the start is where it begins. |
--rhp-gap | leaves space at the start of a Bar: a gap between stacked pieces |
--rhp-label-gap | the space between a Label and its value (or the chart, for edge labels) |
--rhp-label-size | a Label’s font size (12px by default) |
--rhp-tick-width | a Tick’s width (2px by default) |
--rhp-cell-gap | the space around a Cell (1px by default) |
--rhp-toward-end | a direction to use in gradients: linear-gradient(var(--rhp-toward-end), …) fades from a Bar’s start to its end |
Horizontal and vertical
rhp charts can turn: pass orientation="vertical" to the Chart.
The variables above follow the chart as it turns.
For anything else, :horizontal and :vertical target one direction:
.name:vertical { font-size: 11px; }
.bar:horizontal > img { max-width: 300px; }
Put them on the slat or on a block.
For an element inside a block, put them on the block: .bar:vertical .icon.
import { createSignal } from "solid-js";
import { Chart, Plot, Bar, Label, slat } from "@bezda/rhp";
const Planet = slat(
{
css: `
.bar { --rhp-start-radius: 0px; --rhp-end-radius: 8px; }
.value { font-weight: 700; }
.name:vertical { font-size: 11px; }
`,
},
(d) => (
<div>
<Label edge="start" class="name">
{d.planet}
</Label>
<Bar to={d.moons} class="bar" />
<Label at={d.moons} class="value">
{d.moons}
</Label>
</div>
),
);
export default function Moons() {
const [orientation, setOrientation] = createSignal("vertical");
const turn = () =>
setOrientation(
orientation() === "vertical" ? "horizontal" : "vertical",
);
return (
<>
<div class="demo-controls">
<button onClick={turn}>Turn the chart</button>
</div>
<Chart scale={[0, 150]} orientation={orientation()}>
<Plot
planet={["Jupiter", "Saturn", "Uranus", "Neptune"]}
moons={[95, 146, 28, 16]}
>
{Planet}
</Plot>
</Chart>
</>
);
}Colors
Inside a slat’s CSS, the theme’s colors are variables:
var(--rhp-ink)for text,var(--rhp-muted)for quieter text,var(--rhp-grid)for lines,var(--rhp-series-1)tovar(--rhp-series-6)for data,var(--rhp-color)for the block’s owncolor.
The page sets these colors through the theme, described in colors and themes.
Things to know
- Hover whatever should react.
.slat:hover .bar { … }reacts anywhere along the slat, which is an easy thing to point at and lets one rule light up several pieces at once. Hover a block instead when the block is the thing being pointed at: one layer of a stack, one book on a shelf, one cell of a heatmap. - Put your own transitions on elements inside blocks. rhp moves blocks with transitions of its own, and a
transitionset on a block replaces them, so the block would jump to new values. Fade a label’s text, not the label. - The page can still style the chart’s box. Its width, margin, background and border are yours to set on the Chart, with
classorstyle.