Columns in React
Using ApexCharts with React
This Columns example wires ApexCharts into React through the react-apexcharts component.
Install it with npm install react-apexcharts apexcharts, then mount the chart with <Chart type="..." options={options} series={series} />.
import React from 'react'
import ReactApexChart from 'react-apexcharts'
import ApexCharts from 'apexcharts'
import './styles.css'
import 'apexcharts/features/highlight-filter'
// Shared by the vanilla-js, React and Vue builds.
//
// Units sold per year by region (the wholes), and what each sales channel
// contributed to them (the parts). Picking a channel keeps every year and
// region on the chart: each column is drawn faded at its full value, with the
// channel's share solid in front.
var YEARS = ['2015', '2016', '2017', '2018', '2019', '2020', '2021', '2022']
var REGIONS = ['Americas', 'Europe', 'Asia Pacific']
var UNITS = [
[34, 43, 66, 69, 58, 40, 78, 80],
[21, 26, 29, 32, 47, 46, 50, 96],
[19, 24, 28, 26, 38, 31, 52, 38],
]
var CHANNELS = {
online: [
[26, 29, 50, 48, 37, 26, 55, 40],
[14, 17, 21, 20, 23, 34, 38, 70],
[12, 18, 22, 20, 26, 21, 38, 19],
],
store: [
[8, 14, 16, 21, 21, 14, 23, 40],
[7, 9, 8, 12, 24, 12, 12, 26],
[7, 6, 6, 6, 12, 10, 14, 19],
],
}
function seriesFor(channel) {
return REGIONS.map(function (name, i) {
var s = { name: name, data: UNITS[i] }
if (channel) s.highlightData = CHANNELS[channel][i]
return s
})
}
// One call per pick: the parts go in, the chart animates from what is on
// screen. Clearing is the same call without them.
function pickChannel(chart, channel) {
document.querySelectorAll('[data-channel]').forEach(function (b) {
b.classList.toggle('active', b.getAttribute('data-channel') === channel)
})
return chart.updateSeries(seriesFor(channel))
}
function wireChannels(chart) {
document.querySelectorAll('[data-channel]').forEach(function (b) {
b.addEventListener('click', function () {
pickChannel(chart, b.getAttribute('data-channel'))
})
})
}
const ApexChart = () => {
const [state, setState] = React.useState({
series: seriesFor('online'),
options: {
chart: {
id: 'units',
type: 'bar',
height: 380,
toolbar: { show: false },
},
colors: ['#16a34a', '#f59e0b', '#2563eb'],
plotOptions: {
bar: { columnWidth: '78%' },
},
dataLabels: { enabled: false },
stroke: { show: true, width: 1, colors: ['transparent'] },
xaxis: { categories: YEARS },
yaxis: { title: { text: 'Units (thousands)' } },
highlightFilter: { fadeOpacity: 0.2 },
legend: { position: 'bottom' },
tooltip: { shared: true, intersect: false },
},
})
React.useEffect(() => {
// The react-apexcharts wrapper owns the render, so reach the live instance
// by its chart.id. (seriesFor / pickChannel live in the shared head script.)
const timer = window.setInterval(() => {
const chart = ApexCharts.getChartByID('units')
if (!chart) return
window.clearInterval(timer)
wireChannels(chart)
}, 50)
return () => window.clearInterval(timer)
}, [])
return (
<div>
<div className="wrap">
<h1>Highlight a part of every column</h1>
<p>
Pick a sales channel. Every column stays on the chart at its full
value, faded, and the part that channel sold is drawn solid in front
of it from the same baseline. Labels and tooltips state the part.
</p>
<div className="actions">
<span>Channel</span>
<button data-channel="online" className="active">
Online
</button>
<button data-channel="store">In store</button>
<button data-channel="">All (clear)</button>
</div>
<div className="chart-wrap">
<div id="chart">
<ReactApexChart
options={state.options}
series={state.series}
type="bar"
height={380}
/>
</div>
</div>
</div>
</div>
)
}
export default ApexChart