Skip to content
kerfjsGitHub

Chart

The frame every chart shares: title, legend, table view, and loading, empty and error states.

SourcePackage @kerf-js/veneer

Preview

tsx
import { Chart } from '@kerf-js/veneer'import { line } from '@kerf-js/veneer-core/charts'export function Form() {  return (  <Chart    form={line}    title="Monthly bill"    data={TRAFFIC}    x="month"    xName="Month"    series={COST_LINE}    format={dollars}  />  )}const TRAFFIC = [  {    month: 'Nov',    requests: 41.2,    errors: 0.42,    deploys: 88,    cost: 6120,  },  {    month: 'Dec',    requests: 52.8,    errors: 0.51,    deploys: 74,    cost: 6480,  },  {    month: 'Jan',    requests: 47.1,    errors: 0.38,    deploys: 96,    cost: 6390,  },  {    month: 'Feb',    requests: 49.6,    errors: 0.33,    deploys: 104,    cost: 6710,  },  {    month: 'Mar',    requests: 58.3,    errors: 0.47,    deploys: 118,    cost: 7240,  },  {    month: 'Apr',    requests: 61.9,    errors: 0.29,    deploys: 126,    cost: 7380,  },  {    month: 'May',    requests: 66.4,    errors: 0.31,    deploys: 131,    cost: 7690,  },  {    month: 'Jun',    requests: 64.2,    errors: 0.44,    deploys: 122,    cost: 7620,  },  {    month: 'Jul',    requests: 71.5,    errors: 0.27,    deploys: 139,    cost: 8010,  },  {    month: 'Aug',    requests: 74.8,    errors: 0.25,    deploys: 144,    cost: 8230,  },  {    month: 'Sep',    requests: 79.3,    errors: 0.36,    deploys: 152,    cost: 8560,  },  {    month: 'Oct',    requests: 86.1,    errors: 0.22,    deploys: 167,    cost: 8930,  },]const dollars = (v: number) =>  `$${v.toLocaleString('en-US')}`const COST_LINE = [  { key: 'cost', name: 'Monthly bill' },]

Installation

npm install @kerf-js/veneer

Usage

tsx
import { Chart } from '@kerf-js/veneer'<Chart  form={line}  title="Monthly bill"  data={TRAFFIC}  x="month"  xName="Month"  series={COST_LINE}  format={dollars}/>

Loading

Set state to loading to show a placeholder in place of the chart.

tsx
import { Chart } from '@kerf-js/veneer'import { bar } from '@kerf-js/veneer-core/charts'export function Loading() {  return (  <Chart    form={bar}    title="deploys"    state="loading"    data={[]}    x=""    series={[]}  />  )}

Empty

With no data the frame shows empty on its own.

tsx
import { Chart } from '@kerf-js/veneer'import { bar } from '@kerf-js/veneer-core/charts'export function Empty() {  return (  <Chart    form={bar}    title="deploys"    empty={{      title: 'No deploys in this range',      detail: 'Try the last 90 days.',    }}    data={[]}    x=""    series={[]}  />  )}

Error and retry

Press Retry. state swaps the plot in the same frame.

tsx
import { state } from '@kerf-js/core'import { Button, Chart } from '@kerf-js/veneer'import { bar } from '@kerf-js/veneer-core/charts'export function Retry() {  const status = state<'error' | 'loading' | undefined>(    'error',  )  const retry = () => {    status.value = 'loading'    setTimeout(() => (status.value = undefined), 900)  }  return (    <Chart      form={bar}      title="deploys"      state={status.value}      error={{        title: 'Couldn’t load deploys',        detail: 'The metrics service timed out.',      }}      action={        <Button          emphasis="outline"          onClick={retry}        >          Retry        </Button>      }      data={DEPLOYS_BY_TEAM}      x="quarter"      xName="Quarter"      series={TEAMS}    />  )}const DEPLOYS_BY_TEAM = [  {    quarter: 'Q4 2025',    platform: 96,    web: 142,    data: 58,    mobile: 41,  },  {    quarter: 'Q1 2026',    platform: 104,    web: 151,    data: 66,    mobile: 47,  },  {    quarter: 'Q2 2026',    platform: 118,    web: 164,    data: 71,    mobile: 52,  },  {    quarter: 'Q3 2026',    platform: 127,    web: 188,    data: 84,    mobile: 49,  },  {    quarter: 'Q4 2026',    platform: 139,    web: 203,    data: 92,    mobile: 61,  },]const TEAMS = [  { key: 'platform', name: 'Platform' },  { key: 'web', name: 'Web' },  { key: 'data', name: 'Data' },  { key: 'mobile', name: 'Mobile' },]

When to use

Use it for

  • You draw a form of your own and want the shared frame
  • You need to know how charts handle loading and errors

Reach for something else

  • BarChart, when a named chart already fits

Accessibility

  • Every chart has a text alternative and a table view of its numbers, so nothing depends on seeing the marks. See Chart for its keyboard support.

API Reference

PropTypeDefaultDescription
titlestring—The heading.
level2 | 3 | 4 | 6 | 5—The title's heading level: one below the heading the chart sits under. Default 3, a chart in a page section.
descriptionunknown—One supporting line under the title.
toolbarunknown—Beside the view toggle: a layout switch, a range picker.
state"error" | "loading" | "empty"—Replaces the plot, in the same frame. With no data the frame shows empty on its own.
loadingstring—Shows that work is under way.
empty{ title: string; detail?: unknown; }—The title and detail shown in place of the plot when there is no data.
error{ title: string; detail?: unknown; }—A message that marks the field invalid and says why.
actionunknown—The next step under an empty or error state: a Retry button.
dataunknown—The series to draw.
formForm<C>—The layout to draw, from @kerf-js/veneer-core/charts.

Parts

Every element carries a stable name, so you can style it from your own CSS: [data-scope="chart"] [data-part="head"]

headview-toggle

RelatedBar chartLine chart