Askr documentation
UI & Components

Recipes

Recipes: anatomy, keyboard behavior, state, and theming in Askr.

Example

import { createPlot } from '@askrjs/charts';

const Plot = createPlot<ProjectRow>();

<Plot.Root data={rows} rowKey="id" label="Revenue and target">
  <Plot.Bar x="createdAt" y="revenue" fill="team" />
  <Plot.Line x="createdAt" y="target" />
  <Plot.Point x="createdAt" y="target" />
  <Plot.Legend interactive />
</Plot.Root>

Time series

A typical time series pairs `Line` (or `Area`) with a `time`/`utc` scale inferred from a `Date` field, often layering a `movingAverage(field, { window })` trend line over raw `Point` markers. Set `followLatest` on `Root` when the series is live, and use actual `Date` instances in row data rather than transport strings so temporal inference and `utc` selection behave predictably.

Histogram

Bin a numeric or `Date` field with `bin(field, { thresholds })` on `Bar.x`, pair it with `count()` on `y`, and the compiler handles bucket boundaries and default axes automatically. Adding `fill` and `stack` on a categorical field turns the same histogram into a stacked breakdown by category without changing the binning logic.

Stacked bars

`Bar`'s `stack` prop takes the categorical series field directly — `stack="outcome"` — and `normalize` converts the result to percent stacks. For cases where the numeric channel itself needs composing first, the `stack(input, options?)` and `normalize(input)` expression helpers do the same accumulation with explicit `offset` (`zero`, `diverging`, `expand`) and `order` control.

Dashboard polling

For a plot driven by periodic fetches, pass `data` as a reactive `() => readonly Row[]` getter and update the underlying array with `appendPlotRows` or `upsertPlotRows` on each poll, trimming with `trimPlotRows` so the series doesn't grow forever. Combine that with `followLatest` and `PlotApi.resumeLive()` so a viewer who's paused to inspect a spike doesn't get pulled back to the live edge by the next poll.