Material UI is the most popular React UI framework. Created with inspiration from Google's Material Design, Material UI provides a lot of ready-to-use components to build web applications, including dashboards, fast and easy.
In this tutorial, we'll learn how to build a full-stack dashboard with KPIs, charts, and a data table. We'll go from data in the database to the interactive, filterable, and searchable admin dashboard.
We're going to use Cube for our analytics API. It removes all the hustle of building the API layer, generating SQL, and querying the database. It also provides many production-grade features like multi-level caching for optimal performance, multi-tenancy, security, and more.
Update from April 2023. This guide was authored more than 2 years ago and certain parts (e.g., generation of the front-end boilerplate code) are not relevant anymore. Please check up-to-date front-end guides in the blog.
Analytical API with Cube
We're going to build the dashboard for an e-commerce company that wants to track its overall performance and orders' statuses. Let's assume that the company keeps its data in an SQL database. So, in order to display that data on a dashboard, we're going to create an analytical API.
For that, we'll use the Cube command-line utility (CLI).
To create the API, we run this command:
Now we can download and import a sample e-commerce dataset for PostgreSQL:
Once the database is ready, the API can be configured to connect to the database. To do so, we provide a few options via the
.env file in the root of the Cube project folder (
Now we can run the API!
In development mode, the API will also run the Cube Playground. It's a time-saving web application that helps to create a data schema, test out the charts, and generate a React dashboard boilerplate. Run the following command in the Cube project folder:
$ npm run dev
Next, open http://localhost:4000 in your browser.
Cube can generate a simple data schema based on the database’s tables. If you already have a non-trivial set of tables in your database, consider using the data schema generation because it can save time.
For our API, we select the
users tables and click “Generate Schema.” As the result, we'll have 4 generated files in the
schema folder—one schema file per table.
Once the schema is generated, we can build sample charts via web UI. To do so, navigate to the “Build” tab and select some measures and dimensions from the schema.
Frontend with Material UI
Creating a complex dashboard from scratch usually takes time and effort.
The Cube Playground can generate a template for any chosen frontend framework and charting library for you. To create a template for our dashboard, navigate to the "Dashboard App" and use these options:
- Framework: React
- Main Template: React Material UI Static
- Charting Library: Chart.js
Congratulations! Now we have the
dashboard-app folder in our project. This folder contains all the frontend code of our analytical dashboard.
Now it's time to add the Material UI framework. To have a nice-looking dashboard, we're going to use a custom Material UI theme. You can learn about creating your custom Material UI themes from the documentation. For now, let's download a pre-configured theme from GitHub:
Then, let's install the Roboto font which works best with Material UI:
Now we can include the theme and the font to our frontend code. Let's use the
ThemeProvider from Material UI and make the following changes in the
The only thing left to connect the frontend and the backend is a Cube query. We can generate a query in the Cube Playground. Go to http://localhost:4000/, navigate to the "Build" tab, and choose the following query parameters:
- Measure: Orders Count
- Dimension: Orders Status
- Data range: This week
- Chart type: Bar
We can copy the Cube query for the shown chart and use it in our dashboard application.
To do so, let's create a generic
<BarChart /> component which, in turn, will use a
ChartRenderer component. Create the
src/components/BarChart.js file with the following contents:
We'll need some custom options for the
<ChartRenderer /> component. These options will make the bar chart look nice.
helpers folder inside the
dashboard-app/src. Inside the
helpers folder, create the
BarOptions.js file with the following contents:
Let's edit the
src/components/ChartRenderer.js file to pass the options to the
<Bar /> component:
Now the final step! Let's add the bar chart to the dashboard. Edit the
src/pages/DashboardPage.js and use the following contents:
That's all we need to display our first chart! 🎉
In the next part, we'll make this chart interactive by letting users change the date range from "This week" to other predefined values.
Interactive Dashboard with Multiple Charts
In the previous part, we've created an analytical backend and a basic dashboard with the first chart. Now we're going to expand the dashboard so it provides the at-a-glance view of key performance indicators of our e-commerce company.
Custom Date Range
As the first step, we'll let users change the date range of the existing chart.
We'll use a separate
<BarChartHeader /> component to control the date range. Let's create the
src/components/BarChartHeader.js file with the following contents:
Now let's add this
<BarChartHeader /> component to our existing chart. Make the following changes in the
Well done! 🎉 Here's what our dashboard application looks like:
The KPI chart can be used to display business indicators that provide information about the current performance of our e-commerce company. The chart will consist of a grid of tiles, where each tile will display a single numeric KPI value for a certain category.
First, let's use the
react-countup package to add the count-up animation to the values on the KPI chart. Run the following command in the
New we're ready to add new
<KPIChart/> component. Add the
src/components/KPIChart.js component with the following contents:
Let's learn how to create custom measures in the data schema and display their values. In the e-commerce business, it's crucial to know the share of completed orders. To enable our users to monitor this metric, we'll want to display it on the KPI chart. So, we will modify the data schema by adding a custom measure (
percentOfCompletedOrders) which will calculate the share based on another measure (
Let's customize the "Orders" schema. Open the
schema/Orders.js file in the root folder of the Cube project and make the following changes:
- add the
- add the
Now we're ready to add the KPI chart displaying a number of KPIs to the dashboard. Make the following changes to the
Great! 🎉 Now our dashboard has a row of nice and informative KPI metrics:
Now, using the KPI chart, our users are able to monitor the share of completed orders. However, there are two more kinds of orders: "processed" orders (ones that were acknowledged but not yet shipped) and "shipped" orders (essentially, ones that were taken for delivery but not yet completed).
To enable our users to monitor all these kinds of orders, we'll want to add one final chart to our dashboard. It's best to use the Doughnut chart for that, because it's quite useful to visualize the distribution of a certain metric between several states (e.g., all kinds of orders).
First, just like in the previous part, we're going to put the chart options to a separate file. Let's create the
src/helpers/DoughnutOptions.js file with the following contents:
Then, let's create the
src/components/DoughnutChart.js for the new chart with the following contents:
The last step is to add the new chart to the dashboard. Let's modify the
Awesome! 🎉 Now the first page of our dashboard is complete:
If you like the layout of our dashboard, check out the Devias Kit Admin Dashboard, an open source React Dashboard made with Material UI's components.
Multi-Page Dashboard with Data Table
Now we have a single-page dashboard that displays aggregated business metrics and provides at-a-glance view of several KPIs. However, there's no way to get information about a particular order or a range of orders.
We're going to fix it by adding a second page to our dashboard with the information about all orders. On that page, we'll use the Data Table component from Material UI which is great for displaying tabular data. It privdes many rich features like sorting, searching, pagination, inline-editing, and row selection.
However, we'll need a way to navigate between two pages. So, let's add a navigation side bar.
Navigation Side Bar
First, let's downaload a pre-built layout and images for our dashboard application. Run these commands, extract the
layout.zip file to the
src/layouts folder, and the
images.zip file to the
Now we can add this layout to the application. Let's modify the
Wow! 🎉 Here's our navigation side bar which can be used to switch between different pages of the dashboard:
Data Table for Orders
To fetch data for the Data Table, we'll need to customize the data schema and define a number of new metrics: amount of items in an order (its size), an order's price, and a user's full name.
First, let's add the full name in the "Users" schema in the
Then, let's add other measures to the "Orders" schema in the
For these measures, we're going to use the subquery feature of Cube. You can use subquery dimensions to reference measures from other cubes inside a dimension. Here's how to defined such dimensions:
Now we're ready to add a new page. Open the
src/index.js file and add a new route and a default redirect:
The next step is to create the page referenced in the new route. Add the
src/pages/DataTablePage.js file with the following contents:
Note that this component contains a Cube query. Later, we'll modify this query to enable filtering of the data.
All data items are rendered with the
<Table /> component, and changes to the query result are reflected in the table. Let's create this
<Table /> component in the
src/components/Table.js file with the following contents:
The table contains a cell with a custom
<StatusBullet /> component which displays an order's status with a colorful dot. Let's create this component in the
src/components/StatusBullet.js file with the following contents:
Nice! 🎉 Now we have a table which displays information about all orders:
However, its hard to explore this orders using only the controls provided. To fix this, we'll add a comprehensive toolbar with filters and make our table interactive.
First, let's add a few dependencies. Run the command in the
Then, create the
<Toolbar /> component in the
src/components/Toolbar.js file with the following contents:
Note that we have customized the
<Tab /> component with styles and and the
setStatusFilter method which is passed via props. Now we can add this component, props, and filter to the parent component. Let's modify the
Perfect! 🎉 Now the data table has a filter which switches between different types of orders:
However, orders have other parameters such as price and dates. Let's create filters for these parameters. To do so, modify the
To make these filters work, we need to connect them to the parent component: add state, modify our query, and add new props to the
<Toolbar /> component. Also, we will add sorting to the data table. So, modify the
src/pages/DataTablePage.js file like this:
Fantastic! 🎉 We've added some useful filters. Indeed, you can add even more filters with custom logic. See the documentation for the filter format options.
And there's one more thing. We've added sorting props to the toolbar, but we also need to pass them to the
<Table /> component. To fix this, let's modify the
Wonderful! 🎉 Now we have the data table that fully supports filtering and sorting:
User Drill Down Page
The data table we've built allows to find informations about a particular order. However, our e-commerce business is quite successful and has a good return rate which means that users are highly likely to make multiple orders over time. So, let's add a drill down page to explore the complete order informations for a particular user.
As it's a new page, let's add a new route to the
For this route to work, we also need to add the
src/pages/UsersPage.js file with these contents: