Band

Shaded range between per-row upper and lower values on a line chart — min/max ranges, confidence intervals, and Bollinger bands

Preview

Installation

pnpm dlx shadcn@latest add @bklit/band

Band also ships with @bklit/line-chart, so it is already available if you installed the line chart.

Usage

Band fills the area between two data keys on every row — a min/max range, a forecast interval, or Bollinger bands. Use it inside LineChart and place it before your <Line>s so the lines paint on top.

  • It animates in left-to-right with the lines through the shared reveal clip, and morphs with them when data changes.
  • Both edges extend the y-domain, so the band is never clipped at the top or bottom of the plot.
  • It is decorative: the tooltip only reports <Line> series, not the band's edge values.
  • null / non-numeric edge values break the band into separate segments.
import { Band, ChartTooltip, Grid, Line, LineChart, XAxis } from "@bklitui/ui/charts";

const data = [
  { date: new Date("2024-01-01"), value: 142, valueUpper: 160, valueLower: 125 },
  { date: new Date("2024-01-02"), value: 151, valueUpper: 170, valueLower: 133 },
  // ...
];

<LineChart data={data}>
  <Grid horizontal />
  <Band upperKey="valueUpper" lowerKey="valueLower" />
  <Line dataKey="value" />
  <XAxis />
  <ChartTooltip />
</LineChart>

Bollinger bands

withBollingerBands adds a rolling simple moving average (SMA) ± multiplier standard deviations to each row. Rows before the window fills get null for all three keys, which Band renders as a gap (pass minPeriods: 1 to start at the first row instead).

To draw the SMA as a dashed middle line, use a second, zero-height Band with the same key for both edges — unlike Line, it skips the warm-up nulls.

import { Band, withBollingerBands } from "@bklitui/ui/charts";// Adds priceUpper / priceLower / priceSma (null during the warm-up window)const bollingerData = withBollingerBands(data, {dataKey: "price",period: 10,multiplier: 2,});<LineChart data={bollingerData}><Grid horizontal /><Band  upperKey="priceUpper"  lowerKey="priceLower"  fill="var(--chart-1)"  fillOpacity={0.12}  strokeOpacity={0.5}/><Band  upperKey="priceSma"  lowerKey="priceSma"  fillOpacity={0}  stroke="var(--chart-1)"  strokeDasharray="4,4"  strokeOpacity={0.8}  lowerStroke={false}/><Line dataKey="price" strokeWidth={2} /><XAxis /><ChartTooltip /></LineChart>
OptionTypeDefaultDescription
dataKeystringrequiredNumeric key to compute bands for
periodnumber20Rolling window length (rows)
multipliernumber2Standard deviations above and below the SMA
minPeriodsnumberperiodMinimum valid rows in the window before a value is emitted. Set 1 to start the band at the first row using a partial window
upperKeystring`${dataKey}Upper`Key written for the upper band
lowerKeystring`${dataKey}Lower`Key written for the lower band
middleKeystring`${dataKey}Sma`Key written for the SMA

withBollingerBands returns new rows and leaves the input array untouched. It uses the population standard deviation. Non-numeric values are skipped, and a row yields null when its window has fewer than minPeriods valid values — by default the full window must be numeric. With minPeriods: 1 the first row's spread is zero, so the band starts pinched onto the line and widens as the window fills.

Fill types

fillType switches between a flat "solid" fill, a vertical "gradient" (from fillOpacity at the upper edge to gradientToOpacity at the lower edge), and a "pattern" fill using the Background presets.

SolidGradientPattern
<Band  upperKey="valueUpper"  lowerKey="valueLower"  fill="var(--chart-1)"  fillType="gradient" // "solid" | "gradient" | "pattern"  fillOpacity={0.4}  pattern="diagonal"  patternOpacity={0.6}  strokeOpacity={0.5}  />

Edges

Faded edges

fadeEdges fades the fill and strokes to transparent. Horizontal fades span the plot width; vertical fades span the band's own pixel height. fadeSize sets how much of that width or height each fade covers.

<Band  upperKey="valueUpper"  lowerKey="valueLower"  fill="var(--chart-3)"  fillOpacity={0.2}  strokeDasharray="4,4"  strokeOpacity={0.7}  fadeEdges={{ left: true, right: true }}  fadeSize={0.2}  />

Edge strokes

Both edges share stroke, strokeWidth, strokeDasharray, and strokeOpacity. Override one edge with upperStroke / lowerStroke, or pass false to hide it.

<Band  upperKey="valueUpper"  lowerKey="valueLower"  fill="var(--chart-line-primary)"  fillType="gradient"  fillOpacity={0.3}  upperStroke={{ strokeDasharray: "1,3", strokeWidth: 1.5 }}  lowerStroke={false}  />

Band props

PropTypeDefaultDescription
upperKeystringrequiredData key for the upper edge
lowerKeystringrequiredData key for the lower edge
yAxisIdstring"left"Y-scale group id
curveCurveFactorycurveNaturalD3 curve function (match your Line)
fillstringvar(--chart-line-primary)Band color
fillType"solid" | "gradient" | "pattern""solid"Fill style
fillOpacitynumber0.15Solid opacity, or gradient opacity at the upper edge
gradientToOpacitynumber0Gradient opacity at the lower edge
patternPattern preset id"diagonal"Pattern when fillType is "pattern"
patternColorstringfillPattern stroke or tile color
patternScalenumber—Pattern tile scale
patternStrokeWidthnumber—Line stroke width for line-based patterns
patternOpacitynumber1Opacity of the pattern fill
strokestringfillShared edge stroke color
strokeWidthnumber1Shared edge stroke width (0 hides both edges)
strokeDasharraystring— (solid)Shared edge dash pattern
strokeOpacitynumber1Shared edge stroke opacity
upperStrokeBandStrokeProps | false—Override the top edge, or false to hide it
lowerStrokeBandStrokeProps | false—Override the bottom edge, or false to hide it
fadeEdgesBandFadeEdgesfalseFade fill and strokes at the given sides
fadeSizenumber0.15Fraction (0–0.5) of the width / height each fade covers
classNamestring"chart-band"Class on the band's <g>

BandStrokeProps

Every field falls back to the matching shared Band prop.

PropTypeDefaultDescription
strokestringBand stroke ?? fillEdge color
strokeWidthnumberBand strokeWidthEdge width (0 hides the edge)
strokeDasharraystringBand strokeDasharrayEdge dash pattern
strokeOpacitynumberBand strokeOpacityEdge opacity

BandFadeEdges

type BandFadeEdges =
  | boolean
  | "left"
  | "right"
  | { top?: boolean; right?: boolean; bottom?: boolean; left?: boolean };
ValueFades
falseNothing (default)
trueAll four sides
"left" / "right"That horizontal side only
{ left: true, right: true }Any combination of sides

Studio

Edit in Studio

Open in Studio

Open Studio with the line chart and turn on the Band layer in the components panel. Set Mode to Range (upper / lower) or Bollinger bands, then tune fill, edges, and fades — the generated code includes the data shaping.