How we rebuilt our website with the Material UI design system
A few months ago, we embarked on a project to rebuild our marketing website. Although the main purpose was to update the content, user journey, and site mapping, the redesign gave us the opportunity to optimize HOW the site was built.
In choosing a new way to create the site, we went through the process of selecting and implementing a design system. Ultimately, we chose Material UI, an open-source project that builds with React.
This article will walk you through our process of implementing Material UI, so you can use this process for your own website.
Phase 0: Design system selection
Before implementing Material UI (MUI), we took the following steps to evaluate and select the best design system for our team.
Perf testing
Proof of concept
Storybook
Phase 1: Setup
Once we had selected MUI as our design system, the next phase was to set up the theme and prep our site for the redesign. These steps included:
Dependency installation
Theme setup (Typography, Colors)
Initial mapping of atomic components
Storybooking
Access the GitHub repo here: https://github.com/zesty-io/design-system
Implementing ThemeProvider and Theme config into Zesty app root
Button(Zesty) -> Button(MUI)
Kind -> color
Creating documentation mapping legacy to MUI component props
E.g. component props map:
</li> </ul> </li> </ul>
Phase 2: Build
Once we had everything configured, it was time to build out the components. To do this, we had to convert all @zesty-io/core components used in our system to @mui/material and @zesty-io/material components.
The build process consisted of first identifying whether a @zesty-io/core component could just be fully substituted with a @mui/material component or if a new component had to be built on top of MUI with additional functionality and exported from @zesty-io/material.
For either case, we first needed to become familiar with the component's API.
API doc example: https://mui.com/material-ui/api/button/
With this documentation, we could then properly map all of the props we needed to achieve our desired behavior/look.
Phase 3: Testing
Testing is an extremely important part of implementing a new design system. Our testing phase was the most extensive of all the phases we worked through.
Our apps currently rely on Cypress testing to ensure the quality and functionality of our applications. When testing, we often have to target specific elements on the webpage in a myriad of ways such as ID, classname, dom nodes, etc.
Since swapping out existing components removed some of the no longer needed classnames and changed what the component ultimately rendered on the dom, many of our test cases were in need of updates.
The way we did this was rather straightforward. We ran the old tests, observed the ones that failed, and subsequently provided an updated way of selecting that component so that the Cypress runner could find it.
Some tests, however, required significantly more work to update, most notably the components that were rendered in completely different ways. For example, MUI by default renders its popovers in a portal. Therefore, targeting these popovers requires selecting from the root node as opposed to a traditional select within a parent node.
Component Mappings
For our use case, we had to map specific components that were built in Zesty to the Material UI components. If you are taking a legacy design system and converting your content to the new design system of choice, this section can provide some ideas on how we approached this.
Button
The Zesty Button component maps to the MUI Button component
* Note: MUI button type is ‘button’ so if wrapped in a form, you need to specify "submit".
Zesty | MUI |
disabled | disabled |
kind
| variant
|
type
| color
|
size
| size
|
text | NO LONGER SUPPORTED |
startIcon/endIcon: ReactNode | |
fullWidth: boolean |
TextArea - TextField
The Zesty TextArea component maps to the MUI TextField component
https://mui.com/material-ui/api/text-field/
Zesty | MUI |
autocomplete | autocomplete |
defaultValue | defaultValue |
value | value |
placeholder | placeholder |
error | error |
onChange | onChange |
type | type |
multiline = true | |
rows: number | |
minRows: number | |
maxRows: number | |
label=’’Some Input Label’ | |
helperText=’’Some Helper Textl’ | |
size = ‘small’ | |
variant=outlined | |
color = ‘primary’ [default] | |
required: boolean | |
fullWidth: boolean |