Skip to content

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.

Jupiter
95
Saturn
146
Uranus
28
Neptune
16
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:

SelectorWhat it reaches
.rhp-bar, .rhp-dot, .rhp-tick, .rhp-cell, .rhp-area, .rhp-lineevery 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:

Oslo
4°
Madrid
12°
Cairo
19°
Oslo
4°
Madrid
12°
Cairo
19°
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.

VariableWhat it does
--rhp-radiusrounds 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-radiusround one end of a Bar. The end is where its value is; the start is where it begins.
--rhp-gapleaves space at the start of a Bar: a gap between stacked pieces
--rhp-label-gapthe space between a Label and its value (or the chart, for edge labels)
--rhp-label-sizea Label’s font size (12px by default)
--rhp-tick-widtha Tick’s width (2px by default)
--rhp-cell-gapthe space around a Cell (1px by default)
--rhp-toward-enda 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.

Jupiter
95
Saturn
146
Uranus
28
Neptune
16
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) to var(--rhp-series-6) for data,
  • var(--rhp-color) for the block’s own color.

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 transition set 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 class or style.