Skip to main content
Test Double company logo
Services
Services Overview
Holistic software investment consulting
Software Delivery
Accelerate quality software development
Product Management
Launch modern product orgs
Legacy Modernization
Renovate legacy software systems
DevOps
Scale infrastructure smoothly
Upgrade Rails
Update Rails versions seamlessly
Technical Recruitment
Build tech & product teams
Technical Assessments
Uncover root causes & improvements
Case Studies
Solutions
Accelerate Quality Software
Software Delivery, DevOps, & Product Delivery
Maximize Software Investments
Product Performance, Product Scaling, & Technical Assessments
Future-Proof Innovative Software
Legacy Modernization, Product Transformation, Upgrade Rails, Technical Recruitment
About
About
What's a test double?
Approach
Meeting you where you are
Founder's Story
The origin of our mission
Culture
Culture & Careers
Double Agents decoded
Great Causes
Great code for great causes
EDI
Equity, diversity & inclusion
Insights
All Insights
Hot takes and tips for all things software
Leadership
Bold opinions and insights for tech leaders
Developer
Essential coding tutorials and tools
Product Manager
Practical advice for real-world challenges
Say Hello
Test Double logo
Menu
Services
BackGrid of dots icon
Services Overview
Holistic software investment consulting
Software Delivery
Accelerate quality software development
Product Management
Launch modern product orgs
Legacy Modernization
Renovate legacy software systems
Cycle icon
DevOps
Scale infrastructure smoothly
Upgrade Rails
Update Rails versions seamlessly
Technical Recruitment
Build tech & product teams
Technical Assessments
Uncover root causes & improvements
Case Studies
Solutions
Solutions
Accelerate Quality Software
Software Delivery, DevOps, & Product Delivery
Maximize Software Investments
Product Performance, Product Scaling, & Technical Assessments
Future-Proof Innovative Software
Legacy Modernization, Product Transformation, Upgrade Rails, Technical Recruitment
About
About
About
What's a test double?
Approach
Meeting you where you are
Founder's Story
The origin of our mission
Culture
Culture
Culture & Careers
Double Agents decoded
Great Causes
Great code for great causes
EDI
Equity, diversity & inclusion
Insights
Insights
All Insights
Hot takes and tips for all things software
Leadership
Bold opinions and insights for tech leaders
Developer
Essential coding tutorials and tools
Product Manager
Practical advice for real-world challenges
Say hello
Developers
Developers
Developers
Software tooling & tips

Creating advanced line graphs in React with MUI X Charts

Dive into MUI X Charts and unlock the potential of React data visualizations! From basic to advanced features, this guide has you covered.
Josh Justice
|
January 21, 2024
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

MUI (formerly Material UI) is an extensive library of React components styled to match Google’s Material Design. It includes a ton of components, and at the start of November 2023, one more thing was added: Charts. There are a lot of great web and React chart libraries, but MUI X Charts was an easy first choice for my current client because they’ve standardized on MUI org-wide. We’ll keep using MUI X Charts until we have any needs it can’t meet.

MUI X Charts makes it very easy to get a basic chart working with simple components like LineChart and BarChart. If you have more advanced needs, it also provides a chart composition API to let you customize your charts further. Unfortunately, when your needs grow beyond what the simple components can provide, there’s a somewhat steep learning curve (chart jokes!) to get used to the composition API.

To help with the composition API’s learning curve, let’s walk through an example of implementing a chart that goes beyond the basics. First, we’ll look at what we can and can’t accomplish using the basic LineChart component. Then, we’ll see how to switch over to the composition API and re-enable the nice default features of LineChart. Finally, we’ll see how the composition API lets us add additional features, such as reference lines.

Gauging the temperature

To have a chart we can work with post, let’s track the low-temperature data in two cities for a week. Here’s how we could implement that with MUI X Charts’ LineChart component:

import { LineChart } from "@mui/x-charts";
import dayjs from "dayjs";

const xAxisData = [
  new Date("2023-12-04"),
  new Date("2023-12-05"),
  new Date("2023-12-06"),
  new Date("2023-12-07"),
  new Date("2023-12-08"),
  new Date("2023-12-09"),
  new Date("2023-12-10"),
];
const seriesData = [
  [43, 38, 36, 30, 37, 43, 44],
  [31, 28, 27, 27, 33, 40, 35],
];

export default function TemperatureChart() {
  return (
    <div>
      <LineChart
        xAxis={[
          {
            label: "Date",
            data: xAxisData,
            tickInterval: xAxisData,
            scaleType: "time",
            valueFormatter: (date) => dayjs(date).format("MMM D"),
          },
        ]}
        yAxis={[{ label: "Temperature (°F)" }]}
        series={[
          { label: "Atlanta, GA", data: seriesData[0] },
          { label: "Toronto, ON", data: seriesData[1] },
        ]}
        height={400}
      />
    </div>
  );
}

Here’s the line chart it generates for us:

The chart above is a live React component. If you’re on a device with a mouse, try hovering over the chart, and you’ll see a tooltip that provides extra data on the points you’re over.

Say we show this chart to the business, and they love it. They just want one more feature: they want to show a line that indicates the freezing temperature. We check the docs, and we discover that MUI X Charts has the concept of reference lines–we even find a convenient example with reference lines.

But when we check that example’s source code to see how it works, it’s confusing. All the other examples so far on the page use the LineChart component, but this one doesn’t use LineChart at all! Instead, it uses several different components, like ChartContainer and LinePlot. And there’s no information on that page about what these components are. It looks like we’re going to have to figure out how to draw the rest of the chart!

It turns out these components are part of Charts’ composition API, which we’ll need to use if we want to add a reference line.

Composing ourselves

Let’s start by replacing our current functionality with the composition API piece by piece. When we’re done, then we can add in the reference line.

First, let’s pull out a few values that won’t change, so that it’s easier to see what’s specific to the components:

 export default function TemperatureChart() {
+  const xAxis = [
+    {
+      label: 'Date',
+      data: xAxisData,
+      tickInterval: xAxisData,
+      scaleType: 'time',
+      valueFormatter: date => dayjs(date).format('MMM D'),
+    },
+  ];
+  const yAxis = [{label: 'Temperature (°F)'}];
+  const height = 400;
+
   return (
     <div>
       <LineChart
-        xAxis={[
-          {
-            label: 'Date',
-            data: xAxisData,
-            tickInterval: xAxisData,
-            scaleType: 'time',
-            valueFormatter: date => dayjs(date).format('MMM D'),
-          },
-        ]}
-        yAxis={[{label: 'Temperature (°F)'}]}
+        xAxis={xAxis}
+        yAxis={yAxis}
         series={[
           {label: 'Atlanta, GA', data: seriesData[0]},
           {label: 'Toronto, ON', data: seriesData[1]},
         ]}
-        height={400}
+        height={height}
       />
     </div>

Next, let’s replace the LineChart with a composition-based chart. We’ll start with the minimum, a line plot:

-import {LineChart} from '@mui/x-charts';
+import {LinePlot, ResponsiveChartContainer} from '@mui/x-charts';
 import dayjs from 'dayjs';
...
       />
-      <LineChart
+      <ResponsiveChartContainer
         xAxis={xAxis}
         yAxis={yAxis}
         series={[
-          {label: 'Atlanta, GA', data: seriesData[0]},
-          {label: 'Toronto, ON', data: seriesData[1]},
+          {type: 'line', label: 'Atlanta, GA', data: seriesData[0]},
+          {type: 'line', label: 'Toronto, ON', data: seriesData[1]},
         ]}
         height={height}
-      />
+      >
+        <LinePlot />
+      </ResponsiveChartContainer>
     </div>

‍‍

ResponsiveChartContainer is needed to match the automatic width that LineChart allows. If you’re building a chart that has a fixed width, you can use ChartContainer instead.

Note that the lines in the series array changed. LineChart can assume its series are lines—but ResponsiveChartContainer cannot because it supports multiple types of plots. So we have to specify type: 'line' so ResponsiveChartContainer knows what to draw.

When we make this change, we see our two lines but literally nothing else:

With this foundation in place, let’s add back in all the features we had in our original LineChart. I’ll add just a few components at a time so we can understand how each one helps us.

Get back to where we once belonged

At the most basic, we will probably want to add X and Y axes, circles that show each data point, and a legend that describes what the two lines are:

-import {LinePlot, ResponsiveChartContainer} from '@mui/x-charts';
+import {
+  ChartsXAxis,
+  ChartsYAxis,
+  LinePlot,
+  MarkPlot,
+  ResponsiveChartContainer,
+} from '@mui/x-charts';
+import {ChartsLegend} from '@mui/x-charts/ChartsLegend';
 import dayjs from 'dayjs';
...
         height={height}
       >
         <LinePlot />
+        <ChartsXAxis />
+        <ChartsYAxis />
+        <MarkPlot />
+        <ChartsLegend />
       </ResponsiveChartContainer>
     </div>
   );

Note that ChartsLegend is imported from the /ChartsLegend path rather than directly from the package. Interestingly, ChartsLegend is not exported from the root of the package.

Now the chart looks a lot better:

Our original line chart had some interactivity when we hovered over it with the mouse, though. Let’s add a vertical line, highlighting the circles under the line, and a tooltip that shows the X value you have highlighted and the corresponding Y value for each line:

 import {
+  ChartsAxisHighlight,
+  ChartsTooltip,
   ChartsXAxis,
   ChartsYAxis,
+  LineHighlightPlot,
   LinePlot,
...
         <ChartsYAxis />
         <MarkPlot />
         <ChartsLegend />
+        <LineHighlightPlot />
+        <ChartsAxisHighlight x="line" />
+        <ChartsTooltip trigger="axis" />
       </ResponsiveChartContainer>

Note that it’s important that LineHighlightPlot appears after MarkPlot in the JSX: this is what places the circle highlights on top of the circles themselves. If MarkPlot appears second, it will be rendered on top of LineHighlightPlot, and the highlights won’t be visible.

With this, we’ve replicated the functionality we were using from the original LineChart:

Where no chart has gone before

Now we’re ready to add the reference line. The hard part is done; with the composition API groundwork we’ve laid, it’s straightforward:

 import {
   ChartsAxisHighlight,
+  ChartsReferenceLine,
   ChartsTooltip,
...
         <ChartsTooltip trigger="axis" />
+        <ChartsReferenceLine
+          y={32}
+          label="Freezing"
+          labelAlign="end"
+          lineStyle={{stroke: '#128128', strokeDasharray: '3 3'}}
+        />
       </ResponsiveChartContainer>

And now we have our reference line:

Looking at all the code we had to write to replicate the functionality of LineChart, it’s clear how powerful that high-level component is. By comparison, the composition API can feel a bit tedious to use for a case like this, where we need just one additional feature. But the composition API can do a lot more than adding a reference line: for example, it can combine multiple types of plots in one chart, which wouldn’t be possible with LineChart alone. It’s work to learn the composition API, but it can pay off later when you need even more of the advanced features.

The road less traveled

When trying to figure out how to implement the reference line, I had a little trouble navigating my way through the Chart docs. I actually didn’t find the composition API page until after I finished setting up the chart when I was writing this blog post!

After I found the reference line example, I looked for the components I found there in the API Reference section of the docs. Unfortunately, some weren’t listed at all, such as ChartContainer. Others didn’t include any information about what those components are for, such as MarkPlot. If you happen to find the right path through the docs (i.e., the composition API page first), you’ll have the information you need, but if you take a different path, you’ll be left in the dark.

I’ll think about whether there are any suggestions I can propose to the MUI docs that might help me and others discover this more easily in the future. Either way, I hope this walkthrough was helpful to introduce you to MUI X Charts and the composition API!

Stay ahead with software insights

Join the Test Double Dispatch for hot takes, industry trends, tooling tips, and tricks to level up your coding—delivered monthly.

Sign up now

Related Insights

🔗
The nine best recommendations in the new React docs
🔗
Effective React testing
🔗
Model View Controller pattern in React: A deep dive

Explore our insights

See all insights
Leadership
Leadership
Leadership
The business of AI: Solve real problems for real people

After participating in the Perplexity AI Business Fellowship, one thing became clear: the AI hype cycle is missing the business fundamentals. Here are 3 evidence-based insights from practitioners actually building or investing in AI solutions that solve real problems.

by
Cathy Colliver
Leadership
Leadership
Leadership
Pragmatic approaches to agentic coding for engineering leaders

Discover essential practices for AI agentic coding to enhance your team’s AI development learning and adoption, while avoiding common pitfalls of vibe coding.

by
A.J. Hekman
by
Aaron Gough
by
Alex Martin
by
Dave Mosher
by
David Lewis
Developers
Developers
Developers
16 things software developers believe, per a Justin Searls survey

Ruby on Rails developer Justin Searls made a personality quiz, and more than 7,000 software developers filled it out. Here's what it revealed.

by
Justin Searls
Letter art spelling out NEAT

Join the conversation

Technology is a means to an end: answers to very human questions. That’s why we created a community for developers and product managers.

Explore the community
Test Double Executive Leadership Team

Learn about our team

Like what we have to say about building great software and great teams?

Get to know us
Test Double company logo
Improving the way the world builds software.
What we do
Services OverviewSoftware DeliveryProduct ManagementLegacy ModernizationDevOpsUpgrade RailsTechnical RecruitmentTechnical Assessments
Who WE ARE
About UsCulture & CareersGreat CausesEDIOur TeamContact UsNews & AwardsN.E.A.T.
Resources
Case StudiesAll InsightsLeadership InsightsDeveloper InsightsProduct InsightsPairing & Office Hours
NEWSLETTER
Sign up hear about our latest innovations.
Your email has been added!
Oops! Something went wrong while submitting the form.
Standard Ruby badge
614.349.4279hello@testdouble.com
Privacy Policy
© 2020 Test Double. All Rights Reserved.

Stay ahead with software insights

Join the Test Double Dispatch for hot takes, industry trends, tooling tips, and tricks to level up your coding—delivered monthly.

Sign up now