How to Build a React Admin Dashboard
We're going to build a demo Admin Console app step by step during this lesson, adding in React Router as we go.
Building the admin console app#
Let’s start to build out our routing demo admin dashboard. We’re going to use Create React App again to quickly provide us with a scaffolded starting point.
Project setup#
Open up a terminal window and navigate to the parent folder that you want to create the new project in. Next, type the create react-app
command as follows:
yarn create react-app routing-demo
Let the command line finish installing the dependencies, waiting until you see the ‘success’ message and yarn
commands to start and build the app.
Testing the new project#
As we’ve done before, let’s spin up the default app that we just made to make sure we’re starting from a working base.
So, follow the advice in your terminal output and enter the following commands:
cd routing-demo
yarn start
Once the project’s built and launched, you should be able to fire up http://localhost:3000
in a browser and look for the familiar dark background and spinning React logo.
Cleaning up the starter project#
We need to make a few changes to get everything cleaned up and ready for our new routing app.
First, open index.js
, located in /routing-demo/src/
and remove the following, which should be on line 3:
import ‘./index.css'
This just removes a link to the default styles from the project that we won’t need.
After that, locate and delete /src/index.css
and /src/App.css
files.
Finally, open the main App.js
file located at /src/App.js
. Highlight everything in this file and delete it, saving the empty file, ready to be populated with our new routing demo code.
Our project still contains a few default files, components and assets, but we’re not going to worry about them for now as they’re not doing any harm just sitting there and they’re not currently being loaded anyway.
Adding project dependencies#
We’ll create and edit the files we need to get our project running, but first we need to add a couple of dependencies to our project.
Bringing React Router onboard#
The first dependency to add is the React Router Dom NPM package. There is a React Native version of React Router, but the web version is what we need, and that’s React Router Dom.
Back in a terminal window, make sure you’re in the root project location and enter the following command:
yarn add react-router-dom
With that done, we can now import the main package export, BrowserRouter
and all the associated components such as Link
.
Adding Bulma#
For this project, let’s change things up a little with Bulma. This time, instead of referencing the Bulma framework in the index.html
file via a <link />
element, let’s add Bulma via its NPM package.
Still in the terminal window, add Bulma like this:
yarn add bulma
Adding Sass#
In conjunction with our Bulma via Node approach, let’s also add some project styles via Sass this time. Sass is still a popular choice for adding styles to projects, but it requires an additional library, Node Sass, to be added to the Create React App project. Whenever we reference a .scss
file in our files, node-sass
will automatically compile it for us and include the output CSS.
Again, still in the terminal, let’s add the Node Sass package:
yarn add --dev node-sass
We add the -—dev
flag this time around because we wouldn’t want this dependency bundled into the final output of the project if we were to build and deploy it.
Creating our app’s files#
With all our dependencies added, let’s create the files we need for the project and work through them one-by-one.
Note that just about all of the components under the /components
folder will be presentational, containing hard-coded JSX, apart from those explained in further detail, which are mainly concerned with navigational aspects.
App.js
— the familiar project starting point where all the magic happens. It will take care of setting up the main React Router routing function as well as handling the diverse URL paths we will be using./assets/styles.scss
— the Sass version of our standardstyles.css
file where we’ll set some default styles and import the Bulma library./components/AccountManagement.jsx
/components/CreateUser.jsx
/components/Dashboard.jsx
/components/Invoicing.jsx
/components/Nav.jsx
— theNav
component will be used and displayed as part of the header for our dashboard. It will work with our routes file (explained in a moment) to render out top level navigation items and their sub-navigation items as a drop down menu./components/Products.jsx
/components/Sidebar.jsx
— with this component, we’ll dynamically render any sub-navigation items relevant to the particular area we’re currently viewing. It will use a few routing Hooks that React Router provides./components/SignOut.jsx
/components/Support.jsx
/components/Users.jsx
routes.js
- we’re going to keep our app’s routes (and matching components) in this file so that we can dynamically list them in ourApp.js
file.
With the files created, let’s work through them to flesh them out.
Styles.scss#
Open up the /assets/styles.scss
and copy in the following styles:
// IMPORTS
@import "../../node_modules/bulma/css/bulma.min.css";
// VARIABLES
$font-family: "Helvetica neue", Tahoma, sans-serif;
$font-size: 16px;
// GENERAL STYLES
body {
font-family: $font-family;
font-size: $font-size;
}
aside {
&.menu {
background: aliceblue;
padding: 1em;
min-height: 50vh;
}
}
The import
statement at the top of the file brings the Bulma CSS framework styles into the project. Next, we set a couple of SCSS variables and a scant couple of styles to mildly color the sidebar and menu that we’ll be fleshing out later.
Building the presentational components#
The vast majority of our components are purely presentational and have zero working parts. Since they have hard-coded JSX markup peppered with a few Bulma styles, we’re going to move a little quicker to fill them out so we can spend more time focused on the pivotal components that handle the routing logic and navigation elements.
AccountManagement.jsx#
Open up the /components/AccountManagement.jsx
component and scaffold the basic default export as follows:
import React from 'react'
export default () => (
<>
</>
);
We’ll be making use of this exact same template for the remaining presentational components so it might be worth copying and pasting it somewhere as you build these out, before we fill in the specific JSX.
Speaking of which, here’s the JSX that we need to complete the AccountManagement
component.
import React from 'react';
export default () => (
<>
<h1 className="title is-size-2">Manage user account</h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus a lacus sit amet ex accumsan euismod. Donec vehicula fermentum augue, a sodales
justo gravida congue. Cras mattis augue metus, vitae facilisis odio condimentum et. Sed elementum quam ac turpis blandit, eget tincidunt est convallis.
</p>
<div className="field">
<label className="label">Name</label>
<div className="control">
<input className="input" type="text" placeholder="Sally Appleseed" value="Sally Appleseed" />
</div>
</div>
<div className="field">
<label className="label">Username</label>
<div className="control">
<input className="input" type="text" placeholder="sal12_00" value="sal12_00"/>
</div>
</div>
<div className="field">
<label className="label">Email</label>
<div className="control">
<input className="input" type="email" placeholder="Email" value="[email protected]"/>
</div>
</div>
<div className="field">
<label className="label">Department</label>
<div className="control">
<div className="select">
<select value="Management">
<option>Select dropdown</option>
<option>Management</option>
<option>Logistics</option>
<option>Marketing</option>
<option>Maintenance</option>
</select>
</div>
</div>
</div>
<div className="field is-grouped">
<div className="control">
<button className="button is-link">Update user</button>
</div>
<div className="control">
<button className="button is-link is-light">cancel</button>
</div>
</div>
</>
);
We’ve got a title and dummy intro paragraph, followed by a couple of form fields, including a select element. We’ve given each of the forms fields here a value so that it looks like we’ve loaded in some account data to be able to edit, but again, it’s just smoke and mirrors for our purposes.
Finally, at the bottom, we have two dummy buttons that aren’t hooked up to anything.
CreateUser.jsx#
For the CreateUser
component, start out with the default export template we just mentioned, then fill in the rest of the JSX as follows:
import React from 'react';
export default () => (
<>
<h1 className="title is-size-2">Create a new user</h1>
<div className="field">
<label className="label">Name</label>
<div className="control">
<input className="input" type="text" placeholder="Sally Appleseed" />
</div>
</div>
<div className="field">
<label className="label">Username</label>
<div className="control">
<input className="input" type="text" placeholder="sal12_00" />
</div>
</div>
<div className="field">
<label className="label">Email</label>
<div className="control">
<input className="input" type="email" placeholder="Email" />
</div>
</div>
<div className="field">
<label className="label">Department</label>
<div className="control">
<div className="select">
<select>
<option>Select dropdown</option>
<option>Management</option>
<option>Logistics</option>
<option>Marketing</option>
<option>Maintenance</option>
</select>
</div>
</div>
</div>
<div className="field is-grouped">
<div className="control">
<button className="button is-link">Create user</button>
</div>
<div className="control">
<button className="button is-link is-light">cancel</button>
</div>
</div>
</>
);
After the title <h1>
we have some very similar fields to the AccountManagement
component, but this time without the value
attributes, just placeholders for us this time.
Dashboard.jsx#
Open up the Dashboard.jsx
file in the /components
folder and fill out the JSX as follows:
import React from 'react';
export default () => (
<>
<h1 className="title is-size-2">Welcome to the admin console</h1>
<div className="tile is-ancestor">
<div className="tile is-vertical is-8">
<div className="tile">
<div className="tile is-parent is-vertical">
<article className="tile is-child notification is-primary">
<p className="title">Latest news</p>
<p className="subtitle">hot news from our desk to yours</p>
</article>
<article className="tile is-child notification is-warning">
<p className="title">Product updates</p>
<p className="subtitle">latest product releases for you</p>
</article>
</div>
<div className="tile is-parent">
<article className="tile is-child notification is-info">
<p className="title">Important work</p>
<p className="subtitle">Image to follow</p>
<figure className="image is-4by3">
<img src="https://placedog.net/640/480" />
</figure>
</article>
</div>
</div>
<div className="tile is-parent">
<article className="tile is-child notification is-danger">
<p className="title">An exciting title</p>
<div className="content">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus a lacus sit amet ex accumsan euismod. Donec vehicula fermentum augue, a sodales justo gravida congue. Cras mattis augue metus
</p>
</div>
</article>
</div>
</div>
<div className="tile is-parent">
<article className="tile is-child notification is-success">
<div className="content">
<p className="title">Another exciting title</p>
<p className="subtitle">With even more content</p>
<div className="content">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus a lacus sit amet ex accumsan euismod. Donec vehicula fermentum augue, a sodales justo gravida congue. Cras mattis augue metus
</p>
</div>
</div>
</article>
</div>
</div>
</>
);
The dashboard is arguably the most complex-looking as far as JSX structure goes. Generally, dashboards contain a lot of well-structured information in bite-size chunks. To simulate that, we’ve used Bulma’s Tile system, which helps us to create interesting, grid-like layout structures using a series of <div>
elements with the tile
CSS class applied to them.
It is the nesting of these tiled elements that makes the JSX structure look more complex than it really is, but you should be able to follow what’s going on. The end result is quite striking, especially with the different background colors we’ve applied.
However, as before, everything in here is dummy text, placeholder images and hard-coded information.
Invoicing.jsx#
Open up the Invoicing.jsx
file and complete the JSX for the component:
import React from 'react';
export default () => (
<>
<h1 className="title is-size-2">User invoices</h1>
<table className="table">
<thead>
<tr>
<th>Invoice id</th>
<th>Description</th>
<th>Value</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr>
<th>INV_0001123</th>
<td>Work order 2345</td>
<td>£398.78</td>
<td><span className="has-text-primary has-text-weight-bold">PAID</span></td>
<td>
<div className="buttons">
<a className="button is-danger is-small">archive</a>
</div>
</td>
</tr>
<tr>
<th>INV_0001187</th>
<td>Work order 12345</td>
<td>£1268.78</td>
<td><span className="has-text-warning has-text-weight-bold">SENT</span></td>
<td>
<div className="buttons">
<a className="button is-primary is-small">mark paid</a>
<a className="button is-link is-small">resend</a>
<a className="button is-danger is-small">archive</a>
</div>
</td>
</tr>
<tr>
<th>INV_0001123</th>
<td>Work order 9945</td>
<td>£422.99</td>
<td><span className="has-text-primary has-text-weight-bold">PAID</span></td>
<td>
<div className="buttons">
<a className="button is-primary is-small">mark paid</a>
<a className="button is-link is-small">resend</a>
<a className="button is-danger is-small">archive</a>
</div>
</td>
</tr>
<tr>
<th>INV_0001123</th>
<td>Work order 9455</td>
<td>£1118.49</td>
<td><span className="has-text-danger has-text-weight-bold">REFUNDED</span></td>
<td>
<div className="buttons">
<a className="button is-danger is-small">archive</a>
</div>
</td>
</tr>
</tbody>
</table>
</>
);
We have a page title and a Bulma-styled table which contains a few action buttons to simulate possible invoicing actions that our users may wish to take, such as resending an invoice or marking it as paid.
Again, we’ve leaned on the Bulma framework to make our buttons small and colored which adds visual weighting to otherwise boring, regular buttons.
Products.jsx#
For the Products
component, the JSX looks like this:
import React from 'react';
export default () => (
<>
<h1 className="title is-size-2">Products</h1>
<table className="table">
<thead>
<tr>
<th>Product id</th>
<th>Name</th>
<th>SKU</th>
<th>Description</th>
<th>Stock level</th>
</tr>
</thead>
<tbody>
<tr>
<th>12</th>
<td>Large welding torch</td>
<td>SKU_011234</td>
<td>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</td>
<td>56</td>
</tr>
<tr>
<th>13</th>
<td>Soft hammer</td>
<td>SKU_01189</td>
<td>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</td>
<td>12</td>
</tr>
<tr>
<th>14</th>
<td>Calculator, scientific</td>
<td>SKU_023334</td>
<td>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</td>
<td>43</td>
</tr>
<tr>
<th>15</th>
<td>Coffee machine</td>
<td>SKU_010134</td>
<td>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</td>
<td>120</td>
</tr>
<tr>
<th>16</th>
<td>Botanitcal house plant</td>
<td>SKU_01873</td>
<td>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</td>
<td>450</td>
</tr>
</tbody>
</table>
</>
);
We have a page title followed by a regular HTML table that contains a mocked list of possible products. It’s all standard HTML (well, JSX, but it looks identical), barring the addition of the Bulma table
CSS class that makes the magic happen.
SignOut.jsx#
This is far and away the simplest component we’ll be making. All we’re adding to the template default export is a level 1 heading to inform the user that they’ve been logged out of our app.
import React from 'react';
export default () => (
<h1 className="title is-size-2">
You have been signed out!
</h1>
);
Support.jsx#
Open the Support.jsx
file and complete the JSX like this:
import React from 'react';
export default () => (
<>
<h1 className="title is-size-2">Support</h1>
<div className="field">
<label className="label">Name</label>
<div className="control">
<input className="input" type="text" placeholder="Sally Appleseed" />
</div>
</div>
<div className="field">
<label className="label">Email</label>
<div className="control">
<input className="input" type="email" placeholder="Email" />
</div>
</div>
<div className="field">
<label className="label">Type of issue</label>
<div className="control">
<div className="select">
<select>
<option>Select dropdown</option>
<option>Website</option>
<option>Technical</option>
<option>Product A</option>
<option>Product B</option>
</select>
</div>
</div>
</div>
<div className="field">
<label className="label">Describe the issue in detail</label>
<div className="control">
<textarea className="textarea" placeholder="Textarea"></textarea>
</div>
</div>
<div className="field is-grouped">
<div className="control">
<button className="button is-link">Create ticket</button>
</div>
<div className="control">
<button className="button is-link is-light">cancel</button>
</div>
</div>
</>
);
The Support
component will look quite similar to the CreateUser
and AccountManagement
components. We have the ubiquitous page title, and a number of form fields to enable users to send us a message requesting support.
Users.jsx#
For the Users
component, flesh things out with the following JSX:
import React from 'react';
export default () => (
<>
<h1 className="title is-size-2">Team users</h1>
<table className="table">
<thead>
<tr>
<th>User id</th>
<th>Name</th>
<th>Email</th>
<th>Department</th>
<th>Employment date</th>
</tr>
</thead>
<tbody>
<tr>
<th>8</th>
<td>Sally Appleseed</td>
<td>sally@mail.com</td>
<td>Management</td>
<td>01 Jan 2014</td>
</tr>
<tr>
<th>13</th>
<td>Dave Davis</td>
<td>dave.davis@mail.com</td>
<td>Management</td>
<td>07 Mar 2017</td>
</tr>
<tr>
<th>11</th>
<td>Alexis Macintosh</td>
<td>amac@gmail.com</td>
<td>Logistics</td>
<td>24 Apr 2020</td>
</tr>
<tr>
<th>2</th>
<td>Mark Studdart</td>
<td>mark@studdart.co.uk</td>
<td>Marketing</td>
<td>19 May 2016</td>
</tr>
<tr>
<th>56</th>
<td>Don Swanson</td>
<td>d.swanson@goodbuildingcompany.com</td>
<td>Maintenance</td>
<td>13 Feb 2018</td>
</tr>
</tbody>
</table>
</>
);
After a typical level 1 page heading, we have an HTML table filled with simulated user details. To make this table look the business, all we have to add is the single CSS class, table
and Bulma does the heavy styles lifting for us.
This page is a preview of Beginner's Guide to Real World React