import { Legend } from '@coinbase/cds-web-visualization'
Legend displays series information for charts, showing labels and color indicators for each data series. It can be positioned around the chart and supports custom shapes and item components.
Basics
Use the legend prop on chart components to enable a default legend, or pass a Legend component for customization. Legend's flexDirection is automatically set to row for top/bottom legendPosition and column otherwise.
function BasicLegend() { 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 numberFormatter = useCallback( (value) => new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }).format(value), [], ); const chartAccessibilityLabel = `Website traffic across ${pages.length} pages showing page views and unique visitors.`; const getScrubberAccessibilityLabel = useCallback( (index) => { return `${pages[index]}: ${numberFormatter(pageViews[index])} page views, ${numberFormatter(uniqueVisitors[index])} unique visitors.`; }, [pages, pageViews, uniqueVisitors, numberFormatter], ); return ( <LineChart enableScrubbing legend showArea showXAxis showYAxis accessibilityLabel={chartAccessibilityLabel} height={{ base: 200, tablet: 225, desktop: 250 }} legendPosition="right" series={[ { id: 'pageViews', data: pageViews, color: 'rgb(var(--green40))', label: 'Page Views', }, { id: 'uniqueVisitors', data: uniqueVisitors, color: 'rgb(var(--purple40))', label: 'Unique Visitors', areaType: 'dotted', }, ]} xAxis={{ data: pages, }} yAxis={{ showGrid: true, tickLabelFormatter: numberFormatter, }} > <Scrubber accessibilityLabel={getScrubberAccessibilityLabel} /> </LineChart> ); }
Legend will automatically wrap when there are too many items to fit on one line.
function WrappedLegend() { const precipitationData = [ { id: 'northeast', label: 'Northeast', data: [5.14, 1.53, 5.73, 4.29, 3.78, 3.92, 4.19, 5.54, 2.03, 1.42, 2.95, 3.89], color: 'rgb(var(--blue40))', }, { id: 'upperMidwest', label: 'Upper Midwest', data: [1.44, 0.49, 2.16, 3.67, 5.44, 6.21, 4.02, 3.67, 0.92, 1.47, 3.05, 1.48], color: 'rgb(var(--green40))', }, { id: 'ohioValley', label: 'Ohio Valley', data: [4.74, 1.83, 3.1, 5.42, 5.69, 3.29, 5.02, 2.57, 4.13, 0.79, 4.31, 3.67], color: 'rgb(var(--orange40))', }, { id: 'southeast', label: 'Southeast', data: [5.48, 3.11, 5.73, 2.97, 5.45, 3.28, 7.18, 5.67, 7.93, 1.33, 2.69, 3.21], color: 'rgb(var(--yellow40))', }, { id: 'northernRockiesAndPlains', label: 'Northern Rockies and Plains', data: [0.64, 1.01, 1.06, 2.12, 3.34, 2.65, 1.54, 1.89, 0.95, 0.57, 1.23, 0.67], color: 'rgb(var(--indigo40))', }, { id: 'south', label: 'South', data: [4.19, 1.79, 2.93, 3.84, 5.25, 3.4, 4.27, 1.84, 3.08, 0.52, 4.5, 2.62], color: 'rgb(var(--pink40))', }, { id: 'southwest', label: 'Southwest', data: [1.12, 1.5, 1.52, 0.75, 0.76, 1.27, 1.44, 2.01, 0.62, 1.08, 1.23, 0.25], color: 'rgb(var(--purple40))', }, { id: 'northwest', label: 'Northwest', data: [5.69, 3.67, 3.32, 1.95, 2.08, 1.31, 0.28, 0.81, 0.95, 2.03, 5.45, 5.8], color: 'rgb(var(--red40))', }, { id: 'west', label: 'West', data: [3.39, 4.7, 3.09, 1.07, 0.55, 0.12, 0.23, 0.26, 0.22, 0.4, 2.7, 2.54], color: 'rgb(var(--teal40))', }, ]; const xAxisData = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December', ]; const chartAccessibilityLabel = `Regional precipitation data across ${precipitationData.length} US regions over 12 months.`; const getScrubberAccessibilityLabel = useCallback( (index) => { const month = xAxisData[index]; const regionValues = precipitationData .map((region) => `${region.label}: ${region.data[index]} inches`) .join(', '); return `${month} precipitation: ${regionValues}`; }, [xAxisData, precipitationData], ); return ( <LineChart enableScrubbing legend showArea showXAxis showYAxis accessibilityLabel={chartAccessibilityLabel} height={300} legendPosition="bottom" series={precipitationData} xAxis={{ data: xAxisData, label: 'Month', showLine: true, showTickMarks: true }} yAxis={{ label: 'Precipitation (in)', showGrid: true, showLine: true, showTickMarks: true, }} > <Scrubber hideBeaconLabels hideOverlay accessibilityLabel={getScrubberAccessibilityLabel} /> </LineChart> ); }
Position
Use legendPosition to place the legend at different positions around the chart. You can also customize alignment using the justifyContent prop on Legend.
function LegendPosition() { return ( <CartesianChart height={{ base: 150, tablet: 200, desktop: 250 }} inset={{ bottom: 8, left: 0, right: 0, top: 8 }} legend={<Legend justifyContent="flex-end" />} legendPosition="bottom" series={[ { id: 'revenue', label: 'Revenue', data: [455, 520, 380, 455, 285, 235], yAxisId: 'revenue', color: 'rgb(var(--yellow40))', legendShape: 'squircle', }, { id: 'profitMargin', label: 'Profit Margin', data: [23, 20, 16, 38, 12, 9], yAxisId: 'profitMargin', color: 'var(--color-fgPositive)', legendShape: 'squircle', }, ]} xAxis={{ data: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], scaleType: 'band', }} yAxis={[ { id: 'revenue', domain: { min: 0 }, }, { id: 'profitMargin', domain: { max: 100, min: 0 }, }, ]} > <XAxis showLine showTickMarks /> <YAxis showGrid showLine showTickMarks axisId="revenue" position="left" requestedTickCount={5} tickLabelFormatter={(value) => `$${value}k`} width={60} /> <YAxis showLine showTickMarks axisId="profitMargin" position="right" requestedTickCount={5} tickLabelFormatter={(value) => `${value}%`} /> <BarPlot /> </CartesianChart> ); }
Shape Variants
Legend supports different shape variants: pill, circle, square, and squircle. Set the shape on each series using legendShape.
function ShapeVariants() { const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']; return ( <LineChart legend showArea showXAxis showYAxis height={{ base: 200, tablet: 250, desktop: 300 }} legendPosition="left" series={[ { id: 'pill', label: 'Pill', data: [120, 150, 130, 170, 160, 190], color: 'rgb(var(--blue40))', legendShape: 'pill', }, { id: 'circle', label: 'Circle', data: [80, 110, 95, 125, 115, 140], color: 'rgb(var(--green40))', legendShape: 'circle', }, { id: 'square', label: 'Square', data: [60, 85, 70, 100, 90, 115], color: 'rgb(var(--orange40))', legendShape: 'square', }, { id: 'squircle', label: 'Squircle', data: [40, 60, 50, 75, 65, 85], color: 'rgb(var(--purple40))', legendShape: 'squircle', }, ]} xAxis={{ data: months }} yAxis={{ domain: { min: 0 }, showGrid: true }} /> ); }