# LineChart A flexible line chart component for displaying data trends over time. Supports multiple series, custom curves, areas, scrubbing, and interactive data exploration. ## Import ```tsx import { LineChart } from '@coinbase/cds-web-visualization' ``` ## Examples LineChart is a wrapper for [CartesianChart](/components/graphs/CartesianChart) that makes it easy to create standard line charts, supporting a single x/y axis pair. Charts are built using SVGs. ### Basics The only prop required is `series`, which takes an array of series objects. Each series object needs an `id` and a `data` array of numbers. ```jsx live ``` LineChart also supports multiple lines, interaction, and axes. Other props, such as `areaType` can be applied to the chart as a whole or per series. ```jsx live function MultipleLine() { const pages = useMemo( () => ['Page A', 'Page B', 'Page C', 'Page D', 'Page E', 'Page F', 'Page G'], [], ); const pageViews = useMemo(() => [2400, 1398, 9800, 3908, 4800, 3800, 4300], []); const uniqueVisitors = useMemo(() => [4000, 3000, 2000, 2780, 1890, 2390, 3490], []); const chartAccessibilityLabel = `Website visitors across ${pageViews.length} pages.`; const scrubberAccessibilityLabel = useCallback( (index: number) => { return `${pages[index]} has ${pageViews[index]} views and ${uniqueVisitors[index]} unique visitors.`; }, [pages, pageViews, uniqueVisitors], ); const numberFormatter = useCallback( (value: number) => new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }).format(value), [], ); return ( ); } ``` ### Data The data array for each series defines the y values for that series. You can adjust the y values for a series of data by setting the `data` prop on the xAxis. ```jsx live function DataFormat() { const yData = useMemo(() => [2, 5.5, 2, 8.5, 1.5, 5], []); const xData = useMemo(() => [1, 2, 3, 5, 8, 10], []); const chartAccessibilityLabel = `Chart with custom X and Y data. ${yData.length} data points`; const scrubberAccessibilityLabel = useCallback( (index: number) => { return `Point ${index + 1}: X value ${xData[index]}, Y value ${yData[index]}`; }, [xData, yData], ); return ( ); } ``` #### Live Updates You can change the data passed in via `series` prop to update the chart. You can also use the `useRef` hook to reference the scrubber and pulse it on each update. ```jsx live function LiveUpdates() { const scrubberRef = useRef(null); const initialData = useMemo(() => { return sparklineInteractiveData.hour.map((d) => d.value); }, []); const [priceData, setPriceData] = useState(initialData); const lastDataPointTimeRef = useRef(Date.now()); const updateCountRef = useRef(0); const intervalSeconds = 3600 / initialData.length; const maxPercentChange = Math.abs(initialData[initialData.length - 1] - initialData[0]) * 0.05; useEffect(() => { const priceUpdateInterval = setInterval( () => { setPriceData((currentData) => { const newData = [...currentData]; const lastPrice = newData[newData.length - 1]; const priceChange = (Math.random() - 0.5) * maxPercentChange; const newPrice = Math.round((lastPrice + priceChange) * 100) / 100; // Check if we should roll over to a new data point const currentTime = Date.now(); const timeSinceLastPoint = (currentTime - lastDataPointTimeRef.current) / 1000; if (timeSinceLastPoint >= intervalSeconds) { // Time for a new data point - remove first, add new at end lastDataPointTimeRef.current = currentTime; newData.shift(); // Remove oldest data point newData.push(newPrice); // Add new data point updateCountRef.current = 0; } else { // Just update the last data point newData[newData.length - 1] = newPrice; updateCountRef.current++; } return newData; }); // Pulse the scrubber on each update scrubberRef.current?.pulse(); }, 2000 + Math.random() * 1000, ); return () => clearInterval(priceUpdateInterval); }, [intervalSeconds, maxPercentChange]); const chartAccessibilityLabel = useMemo(() => { return `Live Bitcoin price chart. Current price: $${priceData[priceData.length - 1].toFixed(2)}`; }, [priceData]); const scrubberAccessibilityLabel = useCallback( (index: number) => { const price = priceData[index]; return `Bitcoin price at position ${index + 1}: $${price.toFixed(2)}`; }, [priceData], ); return ( ); } ``` #### Missing Data By default, null values in data create gaps in a line. Use `connectNulls` to skip null values and draw a continuous line. Note that scrubber beacons and points are still only shown at non-null data values. ```jsx live function MissingData() { const pages = ['Page A', 'Page B', 'Page C', 'Page D', 'Page E', 'Page F', 'Page G']; const pageViews = [2400, 1398, null, 3908, 4800, 3800, 4300]; const uniqueVisitors = [4000, 3000, null, 2780, 1890, 2390, 3490]; const numberFormatter = useCallback( (value: number) => new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }).format(value), [], ); return ( {/* We can offset the overlay to account for the points being drawn on the lines */} ); } ``` ##### Empty State ```jsx live ``` #### Scales LineChart uses `linear` scaling on axes by default, but you can also use other types, such as `log`. See [XAxis](/components/graphs/XAxis) and [YAxis](/components/graphs/YAxis) for more information. ```jsx live ``` ### Interaction Charts have built in functionality enabled through scrubbing, which can be used by setting `enableScrubbing` to true. You can listen to value changes through `onScrubberPositionChange`. Adding `Scrubber` to LineChart showcases the current scrubber position. ```jsx live function Interaction() { const [scrubberPosition, setScrubberPosition] = useState(); return ( {scrubberPosition !== undefined ? `Scrubber position: ${scrubberPosition}` : 'Not scrubbing'} ); } ``` #### Points You can use `points` from LineChart with `onClick` listeners to render instances of [Point](/components/graphs/Point) that are interactable. ```jsx live function Points() { const keyMarketShiftIndices = [4, 6, 7, 9, 10]; const data = [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58]; return ( keyMarketShiftIndices.includes(dataX) ? { ...props, strokeWidth: 2, stroke: 'var(--color-bg)', radius: 5, onClick: () => alert( `You have clicked a key market shift at position ${dataX + 1} with value ${dataY}!`, ), accessibilityLabel: `Key market shift point at position ${dataX + 1}, value ${dataY}. Click to view details.`, } : false } seriesId="prices" /> ); } ``` ### Animations You can configure chart transitions using `transition` on LineChart and `beaconTransitions` on [Scrubber](/components/graphs/Scrubber). You can also disable animations by setting the `animate` on LineChart to `false`. ```jsx live function Transitions() { const dataCount = 20; const maxDataOffset = 15000; const minStepOffset = 2500; const maxStepOffset = 10000; const domainLimit = 20000; const updateInterval = 500; const myTransitionConfig = { type: 'spring', stiffness: 700, damping: 20 }; const negativeColor = 'rgb(var(--gray15))'; const positiveColor = 'var(--color-fgPositive)'; function generateNextValue(previousValue: number) { const range = maxStepOffset - minStepOffset; const offset = Math.random() * range + minStepOffset; let direction; if (previousValue >= maxDataOffset) { direction = -1; } else if (previousValue <= -maxDataOffset) { direction = 1; } else { direction = Math.random() < 0.5 ? -1 : 1; } let newValue = previousValue + offset * direction; newValue = Math.max(-maxDataOffset, Math.min(maxDataOffset, newValue)); return newValue; } function generateInitialData() { const data = []; let previousValue = Math.random() * 2 * maxDataOffset - maxDataOffset; data.push(previousValue); for (let i = 1; i < dataCount; i++) { const newValue = generateNextValue(previousValue); data.push(newValue); previousValue = newValue; } return data; } const MyGradient = memo((props: DottedAreaProps) => { const areaGradient = { stops: ({ min, max }: AxisBounds) => [ { offset: min, color: negativeColor, opacity: 1 }, { offset: 0, color: negativeColor, opacity: 0 }, { offset: 0, color: positiveColor, opacity: 0 }, { offset: max, color: positiveColor, opacity: 1 }, ], }; return ; }); function CustomTransitionsChart() { const [data, setData] = useState(generateInitialData); useEffect(() => { const intervalId = setInterval(() => { setData((currentData) => { const lastValue = currentData[currentData.length - 1] ?? 0; const newValue = generateNextValue(lastValue); return [...currentData.slice(1), newValue]; }); }, updateInterval); return () => clearInterval(intervalId); }, []); const tickLabelFormatter = useCallback( (value: number) => new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0, }).format(value), [], ); const valueAtIndexFormatter = useCallback( (dataIndex: number) => new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', }).format(data[dataIndex]), [data], ); const lineGradient = { stops: [ { offset: 0, color: negativeColor }, { offset: 0, color: positiveColor }, ], }; return ( ); } return ; } ``` ### Accessibility You can use `accessibilityLabel` on both the chart and the scrubber to provide descriptive labels. The chart's label gives an overview, while the scrubber's label provides specific information about the current data point being viewed. ```jsx live function BasicAccessible() { const data = useMemo(() => [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58], []); // Chart-level accessibility label provides overview const chartAccessibilityLabel = useMemo(() => { const currentPrice = data[data.length - 1]; return `Price chart showing trend over ${data.length} data points. Current value: ${currentPrice}. Use arrow keys to adjust view`; }, [data]); // Scrubber-level accessibility label provides specific position info const scrubberAccessibilityLabel = useCallback( (index: number) => { return `Price at position ${index + 1} of ${data.length}: ${data[index]}`; }, [data], ); return ( ); } ``` When a chart has a visible header or title, you can use `aria-labelledby` to reference it, and still provide a dynamic scrubber accessibility label. ```jsx live function AccessibleWithHeader() { const headerId = useId(); const data = useMemo(() => [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58], []); // Display label provides overview const displayLabel = useMemo( () => `Revenue chart showing trend. Current value: ${data[data.length - 1]}`, [data], ); // Scrubber-specific accessibility label const scrubberAccessibilityLabel = useCallback( (index: number) => { return `Viewing position ${index + 1} of ${data.length}, value: ${data[index]}`; }, [data], ); return ( {displayLabel} ); } ``` ### Styling #### Axes Using `showXAxis` and `showYAxis` allows you to display the axes. For more information, such as adjusting domain and range, see [XAxis](/components/graphs/XAxis) and [YAxis](/components/graphs/YAxis). ```jsx live `Day ${dataX}`, }} yAxis={{ showGrid: true, showLine: true, showTickMarks: true, }} /> ``` #### Gradients Gradients can be applied to the y-axis (default) or x-axis. Each stop requires an `offset`, which is based on the data within the x/y scale and `color`, with an optional `opacity` (defaults to 1). Values in between stops will be interpolated smoothly using [srgb color space](https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperty). ```jsx live function Gradients() { const spectrumColors = [ 'blue', 'green', 'orange', 'yellow', 'gray', 'indigo', 'pink', 'purple', 'red', 'teal', 'chartreuse', ]; const data = [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58]; const [currentSpectrumColor, setCurrentSpectrumColor] = useState('pink'); return ( {spectrumColors.map((color) => ( setCurrentSpectrumColor(color)} style={{ backgroundColor: `rgb(var(--${color}20))`, border: `2px solid rgb(var(--${color}50))`, outlineColor: `rgb(var(--${color}80))`, outline: currentSpectrumColor === color ? `2px solid rgb(var(--${color}80))` : undefined, }} width={{ base: 16, tablet: 24, desktop: 24 }} /> ))} d + 50), // You can create a "discrete" gradient by having multiple stops at the same offset gradient: { stops: ({ min, max }) => [ // Allows a function which accepts min/max or direct array { offset: min, color: `rgb(var(--${currentSpectrumColor}80))` }, { offset: min + (max - min) / 3, color: `rgb(var(--${currentSpectrumColor}80))` }, { offset: min + (max - min) / 3, color: `rgb(var(--${currentSpectrumColor}50))` }, { offset: min + ((max - min) / 3) * 2, color: `rgb(var(--${currentSpectrumColor}50))`, }, { offset: min + ((max - min) / 3) * 2, color: `rgb(var(--${currentSpectrumColor}20))`, }, { offset: max, color: `rgb(var(--${currentSpectrumColor}20))` }, ], }, }, { id: 'xAxisGradient', data: data.map((d) => d + 100), gradient: { // You can also configure by the x-axis. axis: 'x', stops: ({ min, max }) => [ { offset: min, color: `rgb(var(--${currentSpectrumColor}80))`, opacity: 0 }, { offset: max, color: `rgb(var(--${currentSpectrumColor}20))`, opacity: 1 }, ], }, }, ]} strokeWidth={4} yAxis={{ showGrid: true, }} /> ); } ``` You can even pass in a separate gradient for your `Line` and `Area` components. ```jsx live function GainLossChart() { const data = useMemo(() => [-40, -28, -21, -5, 48, -5, -28, 2, -29, -46, 16, -30, -29, 8], []); const negativeColor = 'rgb(var(--gray15))'; const positiveColor = 'var(--color-fgPositive)'; const tickLabelFormatter = useCallback( (value: number) => new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0, }).format(value), [], ); // Line gradient: hard color change at 0 (full opacity for line) const lineGradient = { stops: [ { offset: 0, color: negativeColor }, { offset: 0, color: positiveColor }, ], }; const chartAccessibilityLabel = `Gain/Loss chart showing price changes. Current value: ${tickLabelFormatter(data[data.length - 1])}`; const scrubberAccessibilityLabel = useCallback( (index: number) => { const value = data[index]; const status = value >= 0 ? 'gain' : 'loss'; return `Position ${index + 1} of ${data.length}: ${tickLabelFormatter(value)} ${status}`; }, [data, tickLabelFormatter], ); const GradientDottedArea = memo((props: DottedAreaProps) => ( [ { offset: min, color: negativeColor, opacity: 0.4 }, { offset: 0, color: negativeColor, opacity: 0 }, { offset: 0, color: positiveColor, opacity: 0 }, { offset: max, color: positiveColor, opacity: 0.4 }, ], }} /> )); return ( ({ min, max: max - 16 }), }} > ); } ``` #### Lines You can customize lines by placing props in `LineChart` or at each individual series. Lines can have a `type` of `solid` or `dotted`. They can optionally show an area underneath them (using `showArea`). ```jsx live ``` You can also add instances of [ReferenceLine](/components/graphs/ReferenceLine) to your LineChart to highlight a specific x or y value. ```jsx live ({ min, max: max - 24 }), }} > } dataY={10} stroke="var(--color-fg)" /> ``` #### Points You can also add instances of [Point](/components/graphs/Point) directly inside of a LineChart. ```jsx live function HighLowPrice() { const data = [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58]; const minPrice = Math.min(...data); const maxPrice = Math.max(...data); const minPriceIndex = data.indexOf(minPrice); const maxPriceIndex = data.indexOf(maxPrice); const formatPrice = useCallback((price: number) => { return `$${price.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2, })}`; }, []); return ( ); } ``` #### Scrubber When using [Scrubber](/components/graphs/Scrubber) with series that have labels, labels will automatically render to the side of the scrubber beacon. You can customize the line used for and which series will render a scrubber beacon. You can have scrubber beacon's pulse by either adding `idlePulse` to Scrubber or use Scrubber's ref to dynamically pulse. ```jsx live function StylingScrubber() { const pages = ['Page A', 'Page B', 'Page C', 'Page D', 'Page E', 'Page F', 'Page G']; const pageViews = [2400, 1398, 9800, 3908, 4800, 3800, 4300]; const uniqueVisitors = [4000, 3000, 2000, 2780, 1890, 2390, 3490]; const numberFormatter = useCallback( (value: number) => new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }).format(value), [], ); return ( ); } ``` #### Sizing Charts by default take up `100%` of the `width` and `height` available, but can be customized as any other component. ```jsx live function DynamicChartSizing() { const candles = [...btcCandles].reverse(); const prices = candles.map((candle) => parseFloat(candle.close)); const highs = candles.map((candle) => parseFloat(candle.high)); const lows = candles.map((candle) => parseFloat(candle.low)); const latestPrice = prices[prices.length - 1]; const previousPrice = prices[prices.length - 2]; const change24h = ((latestPrice - previousPrice) / previousPrice) * 100; function DetailCell({ title, description }: { title: string; description: string }) { return ( {title} {description} ); } // Calculate 7-day moving average const calculateMA = (data: number[], period: number): number[] => { const ma: number[] = []; for (let i = 0; i < data.length; i++) { if (i >= period - 1) { const sum = data.slice(i - period + 1, i + 1).reduce((a, b) => a + b, 0); ma.push(sum / period); } } return ma; }; const ma7 = calculateMA(prices, 7); const latestMA7: number = ma7[ma7.length - 1]; const periodHigh = Math.max(...highs); const periodLow = Math.min(...lows); const formatPrice = useCallback((price: number) => { return `$${price.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2, })}`; }, []); const formatPercentage = useCallback((value: number) => { const sign = value >= 0 ? '+' : ''; return `${sign}${value.toFixed(2)}%`; }, []); return ( {/* LineChart fills to take up available width and height */} BTC {formatPrice(latestPrice)} ); } ``` ##### Compact You can also have charts in a compact form. ```jsx live function Compact() { const dimensions = { width: 62, height: 18 }; const sparklineData = prices .map((price) => parseFloat(price)) .filter((price, index) => index % 10 === 0); const positiveFloor = Math.min(...sparklineData) - 10; const negativeData = sparklineData.map((price) => -1 * price).reverse(); const negativeCeiling = Math.max(...negativeData) + 10; const formatPrice = useCallback((price: number) => { return `$${price.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2, })}`; }, []); type CompactChartProps = { data: number[]; showArea?: boolean; color?: string; referenceY: number; }; const CompactChart = memo(({ data, showArea, color, referenceY }: CompactChartProps) => ( )); const ChartCell = memo( ({ data, showArea, color, referenceY, subdetail, }: CompactChartProps & { subdetail: string }) => { const { isPhone } = useBreakpoints(); return ( } media={} onClick={() => console.log('clicked')} spacingVariant="condensed" style={{ padding: 0 }} subdetail={subdetail} title={isPhone ? undefined : assets.btc.name} /> ); }, ); return ( ); } ``` ### Composed Examples #### Asset Price with Dotted Area You can use [PeriodSelector](/components/graphs/PeriodSelector) to have a chart where the user can select a time period and the chart automatically animates. ```jsx live function AssetPriceWithDottedArea() { const BTCTab: TabComponent = memo( forwardRef( ({ label, ...props }: SegmentedTabProps, ref: React.ForwardedRef) => { const { activeTab } = useTabsContext(); const isActive = activeTab?.id === props.id; return ( {label} } {...props} /> ); }, ), ); const BTCActiveIndicator = memo(({ style, ...props }: TabsActiveIndicatorProps) => ( )); const AssetPriceDotted = memo(() => { const currentPrice = sparklineInteractiveData.hour[sparklineInteractiveData.hour.length - 1].value; const tabs = useMemo( () => [ { id: 'hour', label: '1H' }, { id: 'day', label: '1D' }, { id: 'week', label: '1W' }, { id: 'month', label: '1M' }, { id: 'year', label: '1Y' }, { id: 'all', label: 'All' }, ], [], ); const [timePeriod, setTimePeriod] = useState(tabs[0]); const sparklineTimePeriodData = useMemo(() => { return sparklineInteractiveData[timePeriod.id as keyof typeof sparklineInteractiveData]; }, [timePeriod]); const sparklineTimePeriodDataValues = useMemo(() => { return sparklineTimePeriodData.map((d) => d.value); }, [sparklineTimePeriodData]); const sparklineTimePeriodDataTimestamps = useMemo(() => { return sparklineTimePeriodData.map((d) => d.date); }, [sparklineTimePeriodData]); const onPeriodChange = useCallback( (period: TabValue | null) => { setTimePeriod(period || tabs[0]); }, [tabs, setTimePeriod], ); const priceFormatter = useMemo( () => new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', }), [], ); const scrubberPriceFormatter = useMemo( () => new Intl.NumberFormat('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2, }), [], ); const formatPrice = useCallback( (price: number) => { return priceFormatter.format(price); }, [priceFormatter], ); const formatDate = useCallback((date: Date) => { const dayOfWeek = date.toLocaleDateString('en-US', { weekday: 'short' }); const monthDay = date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', }); const time = date.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true, }); return `${dayOfWeek}, ${monthDay}, ${time}`; }, []); const scrubberLabel = useCallback( (index: number) => { const price = scrubberPriceFormatter.format(sparklineTimePeriodDataValues[index]); const date = formatDate(sparklineTimePeriodDataTimestamps[index]); return ( <> {price} USD {date} ); }, [ scrubberPriceFormatter, sparklineTimePeriodDataValues, sparklineTimePeriodDataTimestamps, formatDate, ], ); const chartAccessibilityLabel = `Bitcoin price chart for ${timePeriod.label} period. Current price: ${formatPrice(currentPrice)}`; const scrubberAccessibilityLabel = useCallback( (index: number) => { const price = scrubberPriceFormatter.format(sparklineTimePeriodDataValues[index]); const date = formatDate(sparklineTimePeriodDataTimestamps[index]); return `${price} USD ${date}`; }, [ scrubberPriceFormatter, sparklineTimePeriodDataValues, sparklineTimePeriodDataTimestamps, formatDate, ], ); return ( {formatPrice(currentPrice)}} end={ } style={{ padding: 0 }} title={Bitcoin} /> ); }); return ; } ``` #### Monotone Asset Price You can adjust [YAxis](/components/graphs/YAxis) and [Scrubber](/components/graphs/Scrubber) to have a chart where the y-axis is overlaid and the beacon is inverted in style. ```jsx live function MonotoneAssetPrice() { const prices = sparklineInteractiveData.hour; const priceFormatter = useMemo( () => new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', }), [], ); const scrubberPriceFormatter = useMemo( () => new Intl.NumberFormat('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2, }), [], ); const formatPrice = useCallback( (price: number) => { return priceFormatter.format(price); }, [priceFormatter], ); const CustomYAxisTickLabel = useCallback( (props) => ( ), [], ); const formatDate = useCallback((date: Date) => { const dayOfWeek = date.toLocaleDateString('en-US', { weekday: 'short' }); const monthDay = date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', }); const time = date.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true, }); return `${dayOfWeek}, ${monthDay}, ${time}`; }, []); const scrubberLabel = useCallback( (index: number) => { const price = scrubberPriceFormatter.format(prices[index].value); const date = formatDate(prices[index].date); return ( <> {price} USD {date} ); }, [scrubberPriceFormatter, prices, formatDate], ); const InvertedBeacon = useMemo( () => (props) => ( ), [], ); return ( price.value), color: 'var(--color-fg)', gradient: { axis: 'x', stops: ({ min, max }) => [ { offset: min, color: 'var(--color-fg)', opacity: 0 }, { offset: 32, color: 'var(--color-fg)', opacity: 1 }, ], }, }, ]} style={{ outlineColor: 'var(--color-fg)' }} xAxis={{ range: ({ min, max }) => ({ min: 96, max: max }), }} yAxis={{ position: 'left', width: 0, showGrid: true, tickLabelFormatter: formatPrice, TickLabelComponent: CustomYAxisTickLabel, }} > ); } ``` #### Asset Price Widget ```jsx live function AssetPriceWidget() { const { isPhone } = useBreakpoints(); const prices = [...btcCandles].reverse().map((candle) => parseFloat(candle.close)); const latestPrice = prices[prices.length - 1]; const formatPrice = (price: number) => { return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', }).format(price); }; const formatPercentChange = (price: number) => { return new Intl.NumberFormat('en-US', { style: 'percent', minimumFractionDigits: 2, maximumFractionDigits: 2, }).format(price); }; const percentChange = (latestPrice - prices[0]) / prices[0]; const chartAccessibilityLabel = `Bitcoin price chart. Current price: ${formatPrice(latestPrice)}. Change: ${formatPercentChange(percentChange)}`; const scrubberAccessibilityLabel = useCallback( (index: number) => { return `Bitcoin price at position ${index + 1}: ${formatPrice(prices[index])}`; }, [prices], ); return ( {!isPhone && ( BTC Bitcoin )} {formatPrice(latestPrice)} +{formatPercentChange(percentChange)} ); } ``` #### Service Availability You can have irregular data points by passing in `data` to `xAxis`. ```jsx live function ServiceAvailability() { const availabilityEvents = useMemo( () => [ { date: new Date('2022-01-01'), availability: 79 }, { date: new Date('2022-01-03'), availability: 81 }, { date: new Date('2022-01-04'), availability: 82 }, { date: new Date('2022-01-06'), availability: 91 }, { date: new Date('2022-01-07'), availability: 92 }, { date: new Date('2022-01-10'), availability: 86 }, ], [], ); const chartAccessibilityLabel = `Availability chart showing ${availabilityEvents.length} data points over time`; const scrubberAccessibilityLabel = useCallback( (index: number) => { const event = availabilityEvents[index]; const formattedDate = event.date.toLocaleDateString('en-US', { weekday: 'short', month: 'short', day: 'numeric', year: 'numeric', }); const status = event.availability >= 90 ? 'Good' : event.availability >= 85 ? 'Warning' : 'Critical'; return `${formattedDate}: Availability ${event.availability}% - Status: ${status}`; }, [availabilityEvents], ); return ( event.availability), gradient: { stops: ({ min, max }) => [ { offset: min, color: 'var(--color-fgNegative)' }, { offset: 85, color: 'var(--color-fgNegative)' }, { offset: 85, color: 'var(--color-fgWarning)' }, { offset: 90, color: 'var(--color-fgWarning)' }, { offset: 90, color: 'var(--color-fgPositive)' }, { offset: max, color: 'var(--color-fgPositive)' }, ], }, }, ]} xAxis={{ data: availabilityEvents.map((event) => event.date.getTime()), }} yAxis={{ domain: ({ min, max }) => ({ min: Math.max(min - 2, 0), max: Math.min(max + 2, 100) }), }} > new Date(value).toLocaleDateString()} /> `${value}%`} /> ({ ...props, fill: 'var(--color-bg)', stroke: props.fill, })} seriesId="availability" /> ); } ``` #### Forecast Asset Price You can combine multiple lines within a series to change styles dynamically. ```jsx live function ForecastAssetPrice() { const startYear = 2020; const data = [50, 45, 47, 46, 54, 54, 60, 61, 63, 66, 70]; const currentIndex = 6; const strokeWidth = 3; // To prevent cutting off the edge of our lines const clipOffset = strokeWidth; const axisFormatter = useCallback( (dataIndex: number) => { return startYear + dataIndex; }, [startYear], ); const HistoricalLineComponent = memo((props: SolidLineProps) => { const { drawingArea, getXScale } = useCartesianChartContext(); const xScale = getXScale(); if (!xScale || !drawingArea) return; const currentX = xScale(currentIndex); if (currentX === undefined) return; return ( <> ); }); // Since the solid and dotted line have different curves, // we need two separate line components. Otherwise we could // have one line component with SolidLine and DottedLine inside // of it and two clipPaths. const ForecastLineComponent = memo((props: DottedLineProps) => { const { drawingArea, getXScale } = useCartesianChartContext(); const xScale = getXScale(); if (!xScale || !drawingArea) return; const currentX = xScale(currentIndex); if (currentX === undefined) return; return ( <> ); }); const CustomScrubber = memo(() => { const { scrubberPosition } = useScrubberContext(); const isScrubbing = scrubberPosition !== undefined; // We need a fade in animation for the Scrubber return ( ); }); return ( ); } ``` ## Props | Prop | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `AreaComponent` | `AreaComponent` | No | `-` | Custom component to render line area fill. | | `LineComponent` | `LineComponent` | No | `-` | Component to render the line. Takes precedence over the type prop if provided. | | `alignContent` | `ResponsiveProp
` | No | `-` | - | | `alignItems` | `ResponsiveProp
` | No | `-` | - | | `alignSelf` | `ResponsiveProp
` | No | `-` | - | | `animate` | `boolean` | No | `true` | Whether to animate the chart. | | `areaType` | `gradient \| solid \| dotted` | No | `'gradient'` | The type of area fill to add to the line. | | `as` | `div` | No | `-` | The underlying element or component the polymorphic component will render. Changing as also changes the inherited native props (e.g. href for as=a) and the expected ref type. | | `aspectRatio` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| auto` | No | `-` | - | | `background` | `currentColor \| fg \| fgMuted \| fgInverse \| fgPrimary \| fgWarning \| fgPositive \| fgNegative \| bg \| bgAlternate \| bgInverse \| bgOverlay \| bgElevation1 \| bgElevation2 \| bgPrimary \| bgPrimaryWash \| bgSecondary \| bgTertiary \| bgSecondaryWash \| bgNegative \| bgNegativeWash \| bgPositive \| bgPositiveWash \| bgWarning \| bgWarningWash \| bgLine \| bgLineHeavy \| bgLineInverse \| bgLinePrimary \| bgLinePrimarySubtle \| accentSubtleRed \| accentBoldRed \| accentSubtleGreen \| accentBoldGreen \| accentSubtleBlue \| accentBoldBlue \| accentSubtlePurple \| accentBoldPurple \| accentSubtleYellow \| accentBoldYellow \| accentSubtleGray \| accentBoldGray \| transparent` | No | `-` | - | | `borderBottomLeftRadius` | `0 \| 100 \| 200 \| 300 \| 400 \| 500 \| 600 \| 700 \| 800 \| 900 \| 1000` | No | `-` | - | | `borderBottomRightRadius` | `0 \| 100 \| 200 \| 300 \| 400 \| 500 \| 600 \| 700 \| 800 \| 900 \| 1000` | No | `-` | - | | `borderBottomWidth` | `0 \| 100 \| 200 \| 300 \| 400 \| 500` | No | `-` | - | | `borderColor` | `currentColor \| fg \| fgMuted \| fgInverse \| fgPrimary \| fgWarning \| fgPositive \| fgNegative \| bg \| bgAlternate \| bgInverse \| bgOverlay \| bgElevation1 \| bgElevation2 \| bgPrimary \| bgPrimaryWash \| bgSecondary \| bgTertiary \| bgSecondaryWash \| bgNegative \| bgNegativeWash \| bgPositive \| bgPositiveWash \| bgWarning \| bgWarningWash \| bgLine \| bgLineHeavy \| bgLineInverse \| bgLinePrimary \| bgLinePrimarySubtle \| accentSubtleRed \| accentBoldRed \| accentSubtleGreen \| accentBoldGreen \| accentSubtleBlue \| accentBoldBlue \| accentSubtlePurple \| accentBoldPurple \| accentSubtleYellow \| accentBoldYellow \| accentSubtleGray \| accentBoldGray \| transparent` | No | `-` | - | | `borderEndWidth` | `0 \| 100 \| 200 \| 300 \| 400 \| 500` | No | `-` | - | | `borderRadius` | `0 \| 100 \| 200 \| 300 \| 400 \| 500 \| 600 \| 700 \| 800 \| 900 \| 1000` | No | `-` | - | | `borderStartWidth` | `0 \| 100 \| 200 \| 300 \| 400 \| 500` | No | `-` | - | | `borderTopLeftRadius` | `0 \| 100 \| 200 \| 300 \| 400 \| 500 \| 600 \| 700 \| 800 \| 900 \| 1000` | No | `-` | - | | `borderTopRightRadius` | `0 \| 100 \| 200 \| 300 \| 400 \| 500 \| 600 \| 700 \| 800 \| 900 \| 1000` | No | `-` | - | | `borderTopWidth` | `0 \| 100 \| 200 \| 300 \| 400 \| 500` | No | `-` | - | | `borderWidth` | `0 \| 100 \| 200 \| 300 \| 400 \| 500` | No | `-` | - | | `bordered` | `boolean` | No | `-` | Add a border around all sides of the box. | | `borderedBottom` | `boolean` | No | `-` | Add a border to the bottom side of the box. | | `borderedEnd` | `boolean` | No | `-` | Add a border to the trailing side of the box. | | `borderedHorizontal` | `boolean` | No | `-` | Add a border to the leading and trailing sides of the box. | | `borderedStart` | `boolean` | No | `-` | Add a border to the leading side of the box. | | `borderedTop` | `boolean` | No | `-` | Add a border to the top side of the box. | | `borderedVertical` | `boolean` | No | `-` | Add a border to the top and bottom sides of the box. | | `bottom` | `ResponsiveProp>` | No | `-` | - | | `classNames` | `{ root?: string; chart?: string \| undefined; } \| undefined` | No | `-` | Custom class names for the component. | | `color` | `currentColor \| fg \| fgMuted \| fgInverse \| fgPrimary \| fgWarning \| fgPositive \| fgNegative \| bg \| bgAlternate \| bgInverse \| bgOverlay \| bgElevation1 \| bgElevation2 \| bgPrimary \| bgPrimaryWash \| bgSecondary \| bgTertiary \| bgSecondaryWash \| bgNegative \| bgNegativeWash \| bgPositive \| bgPositiveWash \| bgWarning \| bgWarningWash \| bgLine \| bgLineHeavy \| bgLineInverse \| bgLinePrimary \| bgLinePrimarySubtle \| accentSubtleRed \| accentBoldRed \| accentSubtleGreen \| accentBoldGreen \| accentSubtleBlue \| accentBoldBlue \| accentSubtlePurple \| accentBoldPurple \| accentSubtleYellow \| accentBoldYellow \| accentSubtleGray \| accentBoldGray \| transparent` | No | `-` | - | | `columnGap` | `0 \| 5 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1 \| 1.5 \| 2 \| 3 \| 4 \| 6 \| 7 \| 8 \| 9` | No | `-` | - | | `connectNulls` | `boolean` | No | `-` | When true, the area is connected across null values. | | `curve` | `bump \| catmullRom \| linear \| linearClosed \| monotone \| natural \| step \| stepBefore \| stepAfter` | No | `'bump'` | The curve interpolation method to use for the line. | | `dangerouslySetBackground` | `string` | No | `-` | - | | `display` | `ResponsiveProp` | No | `-` | - | | `elevation` | `0 \| 1 \| 2` | No | `-` | - | | `enableScrubbing` | `boolean` | No | `-` | Enables scrubbing interactions. When true, allows scrubbing and makes scrubber components interactive. | | `flexBasis` | `ResponsiveProp>` | No | `-` | - | | `flexDirection` | `ResponsiveProp` | No | `-` | - | | `flexGrow` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset` | No | `-` | - | | `flexShrink` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset` | No | `-` | - | | `flexWrap` | `ResponsiveProp` | No | `-` | - | | `font` | `ResponsiveProp` | No | `-` | - | | `fontFamily` | `ResponsiveProp` | No | `-` | - | | `fontSize` | `ResponsiveProp` | No | `-` | - | | `fontWeight` | `ResponsiveProp` | No | `-` | - | | `gap` | `0 \| 5 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1 \| 1.5 \| 2 \| 3 \| 4 \| 6 \| 7 \| 8 \| 9` | No | `-` | - | | `grid` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| none` | No | `-` | - | | `gridArea` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| auto` | No | `-` | - | | `gridAutoColumns` | `ResponsiveProp>` | No | `-` | - | | `gridAutoFlow` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| row \| column \| dense` | No | `-` | - | | `gridAutoRows` | `ResponsiveProp>` | No | `-` | - | | `gridColumn` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| auto` | No | `-` | - | | `gridColumnEnd` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| auto` | No | `-` | - | | `gridColumnStart` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| auto` | No | `-` | - | | `gridRow` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| auto` | No | `-` | - | | `gridRowEnd` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| auto` | No | `-` | - | | `gridRowStart` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| auto` | No | `-` | - | | `gridTemplate` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| none` | No | `-` | - | | `gridTemplateAreas` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| none` | No | `-` | - | | `gridTemplateColumns` | `ResponsiveProp>` | No | `-` | - | | `gridTemplateRows` | `ResponsiveProp>` | No | `-` | - | | `height` | `ResponsiveProp>` | No | `-` | - | | `inset` | `number \| Partial` | No | `-` | Inset around the entire chart (outside the axes). | | `justifyContent` | `ResponsiveProp` | No | `-` | - | | `key` | `Key \| null` | No | `-` | - | | `left` | `ResponsiveProp>` | No | `-` | - | | `lineHeight` | `ResponsiveProp` | No | `-` | - | | `margin` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - | | `marginBottom` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - | | `marginEnd` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - | | `marginStart` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - | | `marginTop` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - | | `marginX` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - | | `marginY` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - | | `maxHeight` | `ResponsiveProp>` | No | `-` | - | | `maxWidth` | `ResponsiveProp>` | No | `-` | - | | `minHeight` | `ResponsiveProp>` | No | `-` | - | | `minWidth` | `ResponsiveProp>` | No | `-` | - | | `onChange` | `FormEventHandler` | No | `-` | - | | `onPointClick` | `((event: MouseEvent, point: { x: number; y: number; dataX: number; dataY: number; }) => void)` | No | `-` | Handler for when a point is clicked. Passed through to Point components rendered via points. | | `onScrubberPositionChange` | `((index: number) => void) \| undefined` | No | `-` | Callback fired when the scrubber position changes. Receives the dataIndex of the scrubber or undefined when not scrubbing. | | `opacity` | `number \| ({ base?: Opacity; phone?: Opacity \| undefined; tablet?: Opacity \| undefined; desktop?: Opacity \| undefined; } & number) \| undefined` | No | `1` | Opacity of the lines stroke. Will also be applied to points and area fill. | | `overflow` | `ResponsiveProp` | No | `-` | - | | `padding` | `0 \| 5 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1 \| 1.5 \| 2 \| 3 \| 4 \| 6 \| 7 \| 8 \| 9` | No | `-` | - | | `paddingBottom` | `0 \| 5 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1 \| 1.5 \| 2 \| 3 \| 4 \| 6 \| 7 \| 8 \| 9` | No | `-` | - | | `paddingEnd` | `0 \| 5 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1 \| 1.5 \| 2 \| 3 \| 4 \| 6 \| 7 \| 8 \| 9` | No | `-` | - | | `paddingStart` | `0 \| 5 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1 \| 1.5 \| 2 \| 3 \| 4 \| 6 \| 7 \| 8 \| 9` | No | `-` | - | | `paddingTop` | `0 \| 5 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1 \| 1.5 \| 2 \| 3 \| 4 \| 6 \| 7 \| 8 \| 9` | No | `-` | - | | `paddingX` | `0 \| 5 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1 \| 1.5 \| 2 \| 3 \| 4 \| 6 \| 7 \| 8 \| 9` | No | `-` | - | | `paddingY` | `0 \| 5 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1 \| 1.5 \| 2 \| 3 \| 4 \| 6 \| 7 \| 8 \| 9` | No | `-` | - | | `pin` | `top \| bottom \| left \| right \| all` | No | `-` | Direction in which to absolutely pin the box. | | `points` | `boolean \| ((defaults: PointBaseProps) => boolean \| Partial \| null) \| undefined` | No | `-` | Controls whether and how to render points at each data point in the series. - true: Show all points with default styling - false or undefined: Hide all points - Function: Called for every entry in the data array to customize individual points | | `position` | `ResponsiveProp` | No | `-` | - | | `ref` | `((instance: SVGSVGElement \| null) => void) \| RefObject \| null` | No | `-` | - | | `right` | `ResponsiveProp>` | No | `-` | - | | `rowGap` | `0 \| 5 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1 \| 1.5 \| 2 \| 3 \| 4 \| 6 \| 7 \| 8 \| 9` | No | `-` | - | | `series` | `LineSeries[]` | No | `-` | Configuration objects that define how to visualize the data. Each series supports Line component props for individual customization. | | `showArea` | `boolean` | No | `-` | Whether to show area fill under the line. | | `showXAxis` | `boolean` | No | `-` | Whether to show the X axis. | | `showYAxis` | `boolean` | No | `-` | Whether to show the Y axis. | | `strokeOpacity` | `number` | No | `1` | Opacity of the line | | `strokeWidth` | `number` | No | `2` | Width of the line | | `style` | `CSSProperties` | No | `-` | Custom styles for the root element. | | `styles` | `{ root?: CSSProperties; chart?: CSSProperties \| undefined; } \| undefined` | No | `-` | Custom styles for the component. | | `testID` | `string` | No | `-` | Used to locate this element in unit and end-to-end tests. Under the hood, testID translates to data-testid on Web. On Mobile, testID stays the same - testID | | `textAlign` | `ResponsiveProp
` | No | `-` | - | | `textDecoration` | `ResponsiveProp` | No | `-` | - | | `textTransform` | `ResponsiveProp` | No | `-` | - | | `top` | `ResponsiveProp>` | No | `-` | - | | `transform` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| none` | No | `-` | - | | `transition` | `Orchestration & Repeat & Tween \| Orchestration & Repeat & Spring \| Orchestration & Repeat & Keyframes \| Orchestration & Repeat & Inertia \| Orchestration & Repeat & Just \| Orchestration & Repeat & None \| Orchestration & Repeat & PermissiveTransitionDefinition \| Orchestration & Repeat & Tween & { [key: string]: TransitionDefinition; } \| Orchestration & Repeat & Spring & { [key: string]: TransitionDefinition; } \| Orchestration & Repeat & Keyframes & { [key: string]: TransitionDefinition; } \| Orchestration & Repeat & Inertia & { [key: string]: TransitionDefinition; } \| Orchestration & Repeat & Just & { [key: string]: TransitionDefinition; } \| Orchestration & Repeat & None & { [key: string]: TransitionDefinition; } \| Orchestration & Repeat & PermissiveTransitionDefinition & { [key: string]: TransitionDefinition; }` | No | `-` | Transition configuration for line animations. | | `type` | `solid \| dotted` | No | `'solid'` | The type of line to render. | | `userSelect` | `ResponsiveProp` | No | `-` | - | | `visibility` | `ResponsiveProp` | No | `-` | - | | `width` | `ResponsiveProp>` | No | `-` | - | | `xAxis` | `(Partial & SharedProps & { bandGridLinePlacement?: AxisBandPlacement; bandTickMarkPlacement?: AxisBandPlacement \| undefined; label?: string \| undefined; labelGap?: number \| undefined; minTickLabelGap?: number \| undefined; requestedTickCount?: number \| undefined; showGrid?: boolean \| undefined; showLine?: boolean \| undefined; showTickMarks?: boolean \| undefined; tickMarkSize?: number \| undefined; ticks?: number[] \| ((value: number) => boolean) \| undefined; tickMarkLabelGap?: number \| undefined; tickInterval?: number \| undefined; tickMinStep?: number \| undefined; tickMaxStep?: number \| undefined; } & { className?: string \| undefined; classNames?: { root?: string \| undefined; label?: string \| undefined; tickLabel?: string \| undefined; gridLine?: string \| undefined; line?: string \| undefined; tickMark?: string \| undefined; } \| undefined; style?: CSSProperties \| undefined; styles?: { root?: CSSProperties \| undefined; label?: CSSProperties \| undefined; tickLabel?: CSSProperties \| undefined; gridLine?: CSSProperties \| undefined; line?: CSSProperties \| undefined; tickMark?: CSSProperties \| undefined; } \| undefined; GridLineComponent?: LineComponent \| undefined; LineComponent?: LineComponent \| undefined; TickMarkLineComponent?: LineComponent \| undefined; tickLabelFormatter?: ((value: number) => ChartTextChildren) \| undefined; TickLabelComponent?: AxisTickLabelComponent \| undefined; } & { position?: top \| bottom \| undefined; height?: number \| undefined; }) \| undefined` | No | `-` | Configuration for x-axis. Accepts axis config and axis props. To show the axis, set showXAxis to true. | | `yAxis` | `(Partial & SharedProps & { bandGridLinePlacement?: AxisBandPlacement; bandTickMarkPlacement?: AxisBandPlacement \| undefined; label?: string \| undefined; labelGap?: number \| undefined; minTickLabelGap?: number \| undefined; requestedTickCount?: number \| undefined; showGrid?: boolean \| undefined; showLine?: boolean \| undefined; showTickMarks?: boolean \| undefined; tickMarkSize?: number \| undefined; ticks?: number[] \| ((value: number) => boolean) \| undefined; tickMarkLabelGap?: number \| undefined; tickInterval?: number \| undefined; tickMinStep?: number \| undefined; tickMaxStep?: number \| undefined; } & { className?: string \| undefined; classNames?: { root?: string \| undefined; label?: string \| undefined; tickLabel?: string \| undefined; gridLine?: string \| undefined; line?: string \| undefined; tickMark?: string \| undefined; } \| undefined; style?: CSSProperties \| undefined; styles?: { root?: CSSProperties \| undefined; label?: CSSProperties \| undefined; tickLabel?: CSSProperties \| undefined; gridLine?: CSSProperties \| undefined; line?: CSSProperties \| undefined; tickMark?: CSSProperties \| undefined; } \| undefined; GridLineComponent?: LineComponent \| undefined; LineComponent?: LineComponent \| undefined; TickMarkLineComponent?: LineComponent \| undefined; tickLabelFormatter?: ((value: number) => ChartTextChildren) \| undefined; TickLabelComponent?: AxisTickLabelComponent \| undefined; } & { axisId?: string \| undefined; position?: left \| right \| undefined; width?: number \| undefined; }) \| undefined` | No | `-` | Configuration for y-axis. Accepts axis config and axis props. To show the axis, set showYAxis to true. | | `zIndex` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| auto` | No | `-` | - |