Multi-Axis Charts in Salesforce LWC

Build powerful, interactive data visualizations using Chart.js in Lightning Web Components—ideal for comparing multiple metrics on a single chart.

Component Overview

This implementation delivers a reusable multi-axis chart component for Lightning Web Components, designed to visualize multiple data sets with distinct Y-axes. Ideal for dashboards and analytics use cases, the component:

Key Features

  1. Dual Y-Axes: Visually compare metrics with different value ranges on a single chart
  2. Dynamic Data: Accepts input via public properties for flexible, real-time data binding
  3. Custom Styling: Fully customizable appearance including colors, labels, and legends
  4. Performance Optimized: Smooth rendering and reactivity powered by the lightweight Chart.js library

LWC Component (HTML)

The template defines the chart container and canvas element:

<!-- multiAxisChart.html -->
<template>
    <div class="chart-container" lwc:dom="manual"></div>
</template>

LWC Component (JavaScript)

The controller handles chart initialization and data processing:

// multiAxisChart.js
    import { LightningElement, track, api } from 'lwc';
import chartjs from '@salesforce/resourceUrl/ChartJs';
import { loadScript } from 'lightning/platformResourceLoader';

/**
 * MultiAxisChart - A Lightning Web Component that renders a configurable multi-axis chart using Chart.js.
 * Supports dynamic datasets and multiple y-axes configuration.
 */
export default class MultiAxisChart extends LightningElement {
    // Chart instance reference
    chartInstance;
    
    // Configuration properties exposed to parent components
    @api initChart = false;          // Flag to initialize chart
    @api isChildComponent = false;   // Flag indicating if used as child component
    @api chartDataset = {};          // Dataset for the chart
    @api yAxesConfig = {};           // Y-axes configuration
    
    // Chart data properties
    @track monthLabels = [];         // Labels for x-axis (months)
    @track chartDataValues = [];     // Values for chart data points

    // Style configuration
    @api canvasStyle = "height: 200px !important; width: 99% !important;";

    /**
     * Lifecycle hook - Called when component is inserted into the DOM
     * Initializes the chart
     */
    connectedCallback() {
        this.initializeChart();
    }

    /**
     * Initializes and renders the Chart.js multi-axis chart
     */
    initializeChart() {
        Promise.all([
            loadScript(this, chartjs)
        ]).then(() => {
            // Clear previous chart instance if exists
            if (this.chartInstance) {
                this.chartInstance.destroy();
            }

            // Prepare chart data configuration
            const chartConfig = this.prepareChartConfig();

            // Set canvas dimensions based on component usage (parent/child)
            this.setCanvasDimensions();

            // Get canvas context and create new chart instance
            const canvasContext = this.template
                .querySelector('canvas.multi-axis-chart')
                .getContext('2d');
                
            this.chartInstance = new window.Chart(canvasContext, chartConfig);

        }).catch(error => {
            console.error('Error loading Chart.js:', error);
            // Note: Add proper error handling here (e.g., show toast message)
        });
    }

    /**
     * Prepares the complete configuration object for Chart.js
     * @returns {Object} Complete chart configuration
     */
    prepareChartConfig() {
        // Sample data - Replace with dynamic data from props in actual implementation
        const sampleData = {
            labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
            datasets: [{
                label: 'Dataset 1',
                backgroundColor: 'transparent',
                borderColor: 'green',
                yAxisID: 'y-axis-1',
                data: this.generateRandomData(7, -100, 100)
            }, {
                label: 'Dataset 2',
                backgroundColor: 'transparent',
                yAxisID: 'y-axis-2',
                borderColor: 'red',
                data: this.generateRandomData(7, -100, 100)
            }]
        };

        return {
            type: 'line',
            data: sampleData,
            options: {
                responsive: true,
                title: {
                    display: true,
                    text: 'Multi-Axis Chart'
                },
                tooltips: {
                    mode: 'index',
                    intersect: true
                },
                bezierCurve: false,
                    interaction: {
                        mode: 'index',
                        intersect: false,
                    },
                    stacked: false,
                elements: {
                        line: {
                            tension: 0
                        }
                },
                scales: {
                    yAxes: [{
                        type: 'linear',
                        display: true,
                        position: 'left',
                        id: 'y-axis-1',
                    }, {
                        type: 'linear',
                        display: true,
                        position: 'right',
                        id: 'y-axis-2',
                        gridLines: {
                            drawOnChartArea: false // Prevents grid lines for right axis
                        }
                    }],
                }
            }
        };
    }

    /**
     * Sets the canvas dimensions based on whether component is used as child
     */
    setCanvasDimensions() {
    const chartContainer = this.template.querySelector('.chart-container');
    const height = this.isChildComponent ? '400px' : '250px';
    chartContainer.innerHTML = `<canvas class="multi-axis-chart" style="height: ${height}; width: 99% !important;"></canvas>`;
}

    /**
     * Generates an array of random numbers
     * @param {number} count - Number of data points to generate
     * @param {number} min - Minimum value
     * @param {number} max - Maximum value
     * @returns {Array} Array of random numbers
     */
    generateRandomData(count, min, max) {
        return Array.from({ length: count }, () => 
            Math.round(Math.random() * (max - min) + min)
        );
    }

    /**
     * Generates random RGB color string
     * @returns {string} RGB color string
     */
    generateRandomColor() {
        const r = Math.floor(Math.random() * 255);
        const g = Math.floor(Math.random() * 255);
        const b = Math.floor(Math.random() * 255);
        return `rgb(${r}, ${g}, ${b})`;
    }
}

CSS Styling

Optional CSS for custom chart appearance:

/* multiAxisChart.css */
.chart-container {
    position: relative;
    width: 100%;
    min-height: 300px;
}

Component Output

Conclusion

This multi-axis chart component offers a robust, reusable solution for advanced data visualization in Salesforce.

To implement this component:

  1. Upload Chart.js as a static resource
  2. Deploy the LWC component to your org
  3. Bind your dataset through public properties

Change Chart Type

To customize the chart type (e.g., bar, line, or area), simply update the type property within your dataset. Example: type: 'line' or type: 'bar'