LineChart
Plots one or more series against an ordered category axis. Reach for it when two neighbouring points are part of one continuous change, such as a value over time or a curve over a range, rather than two separate facts.
import { LineChart } from 'neba';
<LineChart
label="Weekly active users by month"
categories={['Jan', 'Feb', 'Mar']}
series={[
{ name: 'Web', data: [1820, 1960, 2140] },
{ name: 'Mobile', data: [940, 1120, 1310] }
]}
/>;The data
Every chart in the library takes the same two props, so a dashboard tile can be switched from one chart to another without rewriting its data.
series is an array of NebaChartSeries. Each entry is one line:
interface NebaChartSeries {
name?: string; // its name in the legend, tooltip and table
data: readonly NebaChartDatum[]; // the values, in category order
color?: NebaColor | string; // overrides the palette slot
hidden?: boolean; // starts hidden; the legend turns it back on
}A NebaChartDatum is a number, a null, or a point:
type NebaChartDatum = number | null | NebaChartPoint;
interface NebaChartPoint {
x?: string | number | Date; // its place on the category axis
y: number | null; // the value
color?: string; // overrides the series colour for this point
label?: ReactNode; // what the tooltip says instead of the number
}null is a gap, not a zero. A sensor that was offline and a month with no sales are different facts, and the chart draws them differently: the line breaks at a null and the point is not drawn. connectNulls bridges it, and should only be used when the gap is an artefact of how the data was collected.
categories names the positions along the x axis. Points may carry their own x instead: whichever matches the shape the data already has.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| series * | NebaChartSeries[] | — | The series. A colour is decided by a series' place in this array, so hiding one from the legend never repaints the survivors |
| categories | (string | number | Date)[] | — | The category axis' labels. Points may carry their own x instead |
| xAxis | NebaChartAxis | — | The category axis |
| yAxis | NebaChartAxis | — | The value axis |
| curve | 'linear' | 'smooth' | 'step' | 'linear' | How the line gets from one point to the next. smooth is a monotone cubic, so it never dips below a value both neighbours are above; step holds each value until the next reading |
| markers | 'none' | 'auto' | 'all' | 'auto' | Dots on the points. auto draws them up to fourteen points. Whatever this says, the point under the pointer always gets one |
| gradient | boolean | false | Fades the line from a paler step of its own hue at the start to the full colour at the end, so the recent end is the loud one |
| connectNulls | boolean | false | Draws straight through a null instead of breaking at it. Only when the gap is an artefact of collection: a bridged gap is a number the chart made up |
| valueLabels | 'none' | 'last' | 'extremes' | 'all' | 'none' | Which values are written on the line. last names where each series ended up, extremes marks its own high and low. The default is none: a number beside every point is the most reliable way to make a chart unreadable |
| stacked | boolean | false | Stacks the series. Rare on a line chart: an AreaChart is the shape that makes stacking legible |
| variantshared | 'solid' | 'outline' | 'text' | 'text' | Weight of the surface. A chart is a drawing rather than a sheet, so this defaults to text and a chart inside a Card draws no second edge. Use outline for one that stands alone |
| sizeshared | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | Axis type, line weight, marker size, and the height, when none is given |
| colorshared | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'primary' | The sheet's colour family. A series' colour does not come from here: the palette or series.color decides that |
| densityshared | 'default' | 'compact' | 'default' | Padding only: never the height, never the type scale |
| elevationshared | 0 | 1 | 2 | 3 | 0 | Drop shadow depth. 0 means no shadow at all |
| height | number | string | size | How tall the drawing is. The axis labels are drawn inside it, so a card sized to the chart is a card the chart fits in |
| label | string | locale's word | The chart's accessible name. Read out in place of the drawing, and the caption of the hidden data table under it. Without it the locale's generic word stands in, but what the chart is *of* can only be said here |
| format | Intl.NumberFormatOptions | — | How numbers are written everywhere they appear: the axis, the tooltip, the value labels, the table. Without it, past ten thousand they are compacted (12.4K) |
| locale | string | — | The language of the chart's own words and dates |
| legend | boolean | NebaChartLegend | series ≥ 2 | Shown automatically from two series up and left off below that: a legend with one swatch restates the title |
| tooltip | boolean | NebaChartTooltip | true | What the pointer uncovers. It never carries a value that is not also in the hidden table |
| empty | ReactNode | — | What to draw when there is nothing to draw |
Every native <div> attribute passes through, along with every Box prop. variant defaults to text and padded to false, so a chart dropped into a Card draws no sheet of its own; variant="outline" gives it one. See prop conventions for the shared axes.
NebaChartAxis
xAxis and yAxis both take this shape.
| Prop | Type | Default | Description |
|---|---|---|---|
| hidden | boolean | false | Leaves the axis undrawn: its rule, its ticks and its labels. The band goes back to the plot |
| label | ReactNode | — | A name for what the axis measures |
| grid | boolean | 값 축은 true / true on the value axis | The gridlines this axis casts across the plot. On for the value axis and off for the category axis; both is graph paper |
| min | number | — | Where the scale starts. Taken from the data otherwise. A BarChart and an AreaChart keep zero; a LineChart crops |
| max | number | — | Where the scale ends |
| tickCount | number | 5 | Roughly how many ticks. The scale still rounds to clean numbers |
| tickFormat | (value, index) => ReactNode | — | How a tick is written, overriding the chart's own format |
| thickness | number | — | How much room the axis keeps for its ticks and label, in pixels. Measured from the ticks otherwise; set it to line two charts up on a dashboard |
NebaChartLegend
| Prop | Type | Default | Description |
|---|---|---|---|
| sideshared | 'top' | 'right' | 'bottom' | 'left' | 'bottom' | Which edge of the plot |
| alignshared | 'start' | 'center' | 'end' | 'center' | Where along that edge |
| interactive | boolean | true | Clicking an entry hides its series; hovering one dims the rest |
| showValue | boolean | false | Draws each series' value at the active category beside its name |
NebaChartTooltip
| Prop | Type | Default | Description |
|---|---|---|---|
| mode | 'index' | 'item' | 'none' | 'index' | index shows every series at the category under the pointer, with a crosshair; item shows the one mark being pointed at |
| crosshair | boolean | true | The line dropped through the plot at the active category, in index mode. It is what says which column the numbers belong to |
| render | (context) => ReactNode | — | Draws the panel. Without it the chart draws its own |
Examples
curve
curve decides how the line gets from one point to the next. linear is the default and claims nothing the data did not say. smooth is a monotone cubic: curved, but it will never dip below a value both of its neighbours are above. step holds each value until the next reading, which is what a rate limit or a plan tier actually did in between.
xAxis · yAxis
A line chart crops its value axis to the data, because a line encodes a position and cropping moves every point by the same amount. Pass yAxis with a min of 0 when zero belongs on the scale.
min, max and tickCount set the range; tickFormat writes each tick; grid: false drops the gridlines; hidden drops the axis entirely and gives its band back to the plot.
connectNulls
valueLabels · gradient · markers
valueLabels writes numbers onto the line: last names where each series ended up, extremes marks each series' own high and low, all labels every point. The default is none: a number beside every point is the most reliable way to make a chart unreadable.
markers puts dots on the points. auto draws them while there are fourteen or fewer; the point under the pointer always gets one regardless.
gradient fades each line from a paler step of its own hue at the start to the full colour at the end.
legend
The legend appears automatically from two series up and is left off below that. side and align place it; clicking an entry hides its series, and the survivors keep the colour they had. legend={false} removes it, interactive: false makes it a key rather than a control.
Colour
Series take palette slots in the order they are passed: eight hues, fixed, never cycled. A ninth series is not a ninth colour; fold the tail into an "Other" series or draw a second chart.
series.color overrides the slot with a NebaColor family or any CSS colour, and a point's own color overrides that for one mark. See colour for the ramp and what it is solved for.
<LineChart
series={[
{ name: 'Errors', data: errors, color: 'danger' },
{ name: 'Warnings', data: warnings, color: 'warning' }
]}
/>format
format takes Intl.NumberFormat options and applies everywhere a number appears: the axis, the tooltip, the value labels, the table. Without it, axis ticks past ten thousand are compacted (12.4K).
<LineChart format={{ style: 'currency', currency: 'USD', maximumFractionDigits: 0 }} … />
<LineChart format={{ style: 'percent', maximumFractionDigits: 1 }} … />Accessibility
- Every chart renders a table of its data, visually hidden and available to assistive technology.
labelbecomes its caption and the chart's accessible name. A tooltip never carries a value that is not also in that table. - The plot is focusable.
←and→step the crosshair between categories,HomeandEndjump to the ends,Escapeclears it, so the tooltip is reachable without a pointer. - The legend is a list of
aria-pressedbuttons, so which series are drawn is stated rather than implied by colour. - Identity is never carried by colour alone: the legend is always present from two series up, and the palette's adjacent pairs are verified against simulated protanopia and deuteranopia.