react-chartjs-2 fill property not working: register Filler
Why a line chart ignores fill: true, the console warning that names the cause, the per-chart and chart.js/auto alternatives, and what each one costs in bundle size.
TL;DR#
fill: true on a react-chartjs-2 dataset does nothing when Chart.js is imported the tree-shaken way, because the area under a line is drawn by the Filler plugin, and that plugin is never registered. Add Filler to your ChartJS.register(...) call (or import chart.js/auto). Chart.js 4 prints a console warning naming the missing plugin; Chart.js 3.9.1 draws nothing and prints nothing.
import { Chart as ChartJS, Filler } from 'chart.js';
ChartJS.register(Filler);This is the Stack Overflow question "react-chartjs-2 fill property not working?", whose accepted answer gives that registration. The rest of this page shows why it works, how to confirm it, and the two other ways to get the same result.
The symptom: a line, no area, and one console warning#
The asker's dataset looked like this: a filled line with a purple border and the same colour as background.
const data = {
labels,
datasets: [
{
label: 'Balance',
data: history.balances.map((item) => item.balance),
fill: true,
borderColor: 'rgba(190, 56, 242, 1)',
backgroundColor: 'rgba(190, 56, 242, 1)',
tension: 0.3,
},
],
};The chart renders the curve but no area below it. On Chart.js 4 the console shows this warning, which is the whole diagnosis:
Tried to use the 'fill' option without the 'Filler' plugin enabled. Please import and register the 'Filler' plugin and make sure it is not disabled in the optionsWhy the area is never drawn#
Chart.js ships as a tree-shakeable library. The integration guide says it plainly: "Chart.js is tree-shakeable, so it is necessary to import and register the controllers, elements, scales and plugins you are going to use." Its list of plugins describes Filler as "used to fill area described by LineElement", and the area chart page repeats that the fill option "is implemented by the filler plugin".
So fill is not a property the line element paints itself. It is an option that a separate plugin reads and turns into a filled path, by default in its beforeDatasetDraw hook, just before each dataset's line is drawn (source of the filler plugin, where drawTime defaults to that hook). No plugin, no area.
Why there is no error, only a warning. Chart.js treats a missing plugin differently from a missing controller or scale. When a chart starts, it builds its plugin list by walking whatever is in the registry, plus any plugins passed in the chart config (allPlugins() in core.plugins.js). Nothing asks for filler by name, so a missing Filler is simply absent from that list. A scale, by contrast, is looked up by its id, and an unregistered one throws. What Chart.js 4 adds is a check: in v4.6.1, DatasetController.initialize() tests this.options.fill && !this.chart.isPluginEnabled('filler') and calls console.warn (core.datasetController.js at v4.6.1). The same file at the v3.9.1 tag has no such check; it first appears at the v4.0.0 tag. The question was asked in December 2021; the npm registry shows only 3.x releases at that date, the first 4.x release being 4.0.1 in November 2022. No release available then printed this warning, and the question quotes no console message.
Why react-chartjs-2 does not do it for you. Importing Line from react-chartjs-2 does register something, but only the controller. In typedCharts.tsx at v5.3.1, each typed component is created with createTypedChart('line', LineController), which calls ChartJS.register(registerables) with that single controller. Elements, scales and plugins stay your job.
Fix: register Filler next to the rest of your line chart#
- Find the file where you call
ChartJS.register. It usually sits next to the chart component. AddFillerto both the import and the register call:
import {
Chart as ChartJS,
LineElement,
PointElement,
CategoryScale,
LinearScale,
Filler,
Tooltip,
Legend,
} from 'chart.js';
import { Line } from 'react-chartjs-2';
ChartJS.register(LineElement, PointElement, CategoryScale, LinearScale, Filler, Tooltip, Legend);
export function BalanceChart({ labels, balances }) {
const data = {
labels,
datasets: [
{
label: 'Balance',
data: balances,
fill: true,
borderColor: 'rgba(190, 56, 242, 1)',
backgroundColor: 'rgba(190, 56, 242, 0.25)',
tension: 0.3,
},
],
};
return <Line data={data} />;
}LineController is not in the list because importing Line registered it already. Listing it anyway changes nothing: the registry returns early for an id it already holds (core.typedRegistry.js at v4.6.1).
-
If the dataset sets
fill: true, also check that nothing turns the plugin off. The warning text ends with "make sure it is not disabled in the options":options.plugins.filler: falsedisables a registered Filler for that chart, with the same result as never registering it. -
Optional, and separate from the fix: the asker used the same opaque colour for border and background, so the filled area and the line merge into one block. A lower alpha on
backgroundColor, as above, keeps the line visible over the area.
fill: true is kept for backward compatibility and is equivalent to fill: 'origin', which fills to the scale's base value: zero when the axis spans it, otherwise the axis bound nearest to zero, so an all-positive balance series fills down to the bottom of its axis (getBaseValue() in core.scale.js). The area chart docs list the other targets, such as 'start', 'end', another dataset by index, or an axis value; every one of them needs the same Filler plugin.
Verify the fix#
Reload the page and check two things: the area is painted, and the warning above is gone from the console. To check from code, Chart.js exposes isPluginEnabled on the chart instance; with a ref on the Line component, chartRef.current.isPluginEnabled('filler') must return true.
The mechanism was reproduced outside the browser on 30 October 2026, with Node 26.7.0 on Windows 11, chart.js 4.6.1 and react-chartjs-2 5.3.1. Docker was not available for this run, and no browser rendered anything: the canvas was a stub whose 2D context counts its ctx.fill() calls, with points hidden so that only the area could call it. With the question's dataset and every line chart component registered except Filler:
Tried to use the 'fill' option without the 'Filler' plugin enabled. Please import and register the 'Filler' plugin and make sure it is not disabled in the options
[without-filler] isPluginEnabled('filler') = false; ctx.fill() calls = 0The one change, Filler added to Chart.register:
[with-filler] isPluginEnabled('filler') = true; ctx.fill() calls = 1Registering Filler but setting options.plugins.filler: false brought the warning back and isPluginEnabled('filler') to false. Importing Line from react-chartjs-2 and asking the registry directly confirmed what the source says:
after importing { Line } from react-chartjs-2: 'line' is registered
after importing { Line } from react-chartjs-2: "filler" is not a registered plugin.The same script against the ESM build of chart.js 3.9.1 drew no area without Filler and printed nothing to the console.
One email a month — the latest explained errors
What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.
Two other ways to enable Filler, and what they cost#
One chart only. Chart.js accepts plugin objects in the chart config, and react-chartjs-2 forwards its plugins prop to it (chart.tsx at v5.3.1). <Line data={data} plugins={[Filler]} /> fills that chart without registering Filler globally. Reproduced: with Filler absent from Chart.register and passed as plugins: [Filler] in the config, the run reported isPluginEnabled('filler') = true and one area fill.
Everything at once. import Chart from 'chart.js/auto' registers every controller, element, scale and plugin; its entry file is Chart.register(...registerables). The integration guide offers it "if you don't care about the bundle size". The difference is measurable. Reproduced with esbuild 0.25.12 (--bundle --minify --format=esm), an entry that registers only the line chart pieces plus Filler came to 146337 bytes minified, 51862 gzipped; an entry importing chart.js/auto came to 206084 bytes minified, 71097 gzipped. That is an esbuild measurement of Chart.js alone, not the size of a Next.js page, but the gap is what auto adds to whichever client bundle loads the chart. For a dashboard that only draws lines, the explicit list is the lighter choice; the Next.js performance guide covers analysing those client bundles.
When a registration fix leads to a thrown error instead#
Trimming registrations to save bytes is where the next error usually comes from. Unlike Filler, a missing scale is not silent. With CategoryScale removed from the register call, the same reproduction threw on chart creation:
Error: "category" is not a registered scale.The id in quotes names what to add: category is CategoryScale, linear is LinearScale, and the same message format covers controllers and elements. The integration guide lists the bare minimum per chart type; for a line chart that is LineController, LineElement, PointElement, CategoryScale and LinearScale.
In the Next.js App Router, one more boundary applies. The react-chartjs-2 5.3.1 build carries no 'use client' directive and its chart component uses useRef and useEffect, so the file that renders Line has to sit under a client boundary. If importing it from a page throws a hooks error, the client boundary fix for third-party components shows where the directive goes. Unlike the case in localStorage is not defined after 'use client', react-chartjs-2 creates the chart inside a useEffect (chart.tsx), so the canvas is only touched in the browser.
The question looks like a styling bug, but it is a registration bug: Chart.js only knows what it has been given, and only the missing scales and controllers announce themselves with an error. For the area under a line, look for Filler in the register call first, then for a filler: false in the options, and keep chart.js/auto for prototypes where the extra bytes do not matter.
Further reading: Fix: Objects Are Not Valid as a React Child.
Frequently Asked Questions
Still stuck? Paste your error.
Paste the error message or stack trace — we check it against every fix and tool on the site.
Continue Reading
Fix: Objects Are Not Valid as a React Child
The 2015 bug reproduced today, the exact modern error text, what the production build shows instead, and the one-line fix for every cause.
Fix localStorage is not defined after 'use client' (Next.js)
The cookie banner from the Stack Overflow question, rebuilt on Next.js 16.3.8: why 'use client' does not stop the crash, the useEffect fix, and the other errors Node 25 and 26 print.
Minified React error #425: Text Mismatch After Deploy
Decode #425 and its companion #423, reproduce both triggers from the Stack Overflow thread on Next.js 12.2.5, and see what React 19 prints instead.


