🚨 We are very excited to announce the release of a new package: @material-ui/system. ✨✨

While this project is still in alpha, you can already give it a try. This effort is part of our Roadmap for Q4 2018 and Q1 2019.

@material-ui/system is a utility package delivering style functions for building powerful design systems.

The problem

Material-UI is well known for its low-level React components. Our most used components are the buttons and the text fields. But you can’t build a whole website/application with buttons, text fields, app bars, drawers, etc., alone.

You have to assemble these components in a coherent and meaningful way.

We can draw a parallel with the Atomic design methodology that specifies five layers of abstractions:

five distinct stages

So far, Material-UI has been focusing on solving the atomic and molecular layer problems. But what about the organism layer? How can we effectively build them?

Note: we are also working on solving the templates problem with a theme marketplace, but it’s a topic for another blog post.

Until now, the best way to assemble the piece together was to write custom CSS. The Grid component only solves a fraction of the problem. Let’s take the Banner component as an example. The Material-UI library doesn’t provide a component yet, it’s up to the users to put all the pieces together.

The Banner component.

The source of the Banner component using custom CSS. A live demo.

The Banner component requires two custom CSS rules. This complexity can’t be removed, it’s structural. But what if they were a way to hide it?

The step is to write new components to abstract the logic and provide a new API. It works, but it isn’t flexible. What if they were a better way?

The solution

The solution we came up with is heavily inspired by prior art. Here are some benchmarks.

Static CSS

The first interesting solution to look at is the static CSS approach.

In this solution, you generate one big CSS file, ahead of time, containing all the utility class names you might want to use.

You have to find a balance between the size of the generated CSS file

and the features you want to use. It’s the same tradeoff we have made with our grid component. Some examples are:

Tailwind CSS. Tailwind exposes a lot of responsive CSS classes, it comes with a price, their documentation website requests 60 kB gzipped of CSS.

Bootstrap CSS helpers. Bootstrap has CSS helpers like Tailwind but they support fewer values and have less responsive variants.

Dynamic CSS

The second solution was made possible by the CSS-in-JS work the React community has seen these past few years. Instead of generating all the CSS at build time, it dynamically generates the CSS at runtime. Some examples are:

@material-ui/system follows this approach, it’s a utility package delivering style functions. But what’s a style function?

It’s a function that takes React properties as an argument and returns a style object.

It’s especially useful with styled-components, emotion or JSS as they accept these functions as argument. People can combine the two to get a Box component:

The source

The output

These style functions come with some key features:

⚛️ Access the theme values directly from the component props.

🦋 Encourage UI consistency.

🌈 Write responsive style effortlessly.

🦎 Work with any theme object.

💅 Work with the most popular CSS-in-JS solutions.

📦 Less than 4 KB gzipped.

🚀 Fast enough not to be a bottleneck at runtime.

Going back to our earliest Banner example, the code looks like this now:

The source of the Banner component using the new Box. A live demo.

This new Box component makes it easier to delete, move and write code. There are no style sheets (makeStyles/withStyles) to keep track of.

Build your own design system

The Box component of Material-UI demonstrates how powerful the style functions are. The component is packaging all the style functions we are exposing.

Now, you can take advantage of the style functions outside of the Material Design system. Let’s say you want to create a Text component for handling the typography of your custom design system. You can implement it like this:

The @material-ui/system package was designed as a utility tool. In the future, we will look into using it directly in the core components. For instance, people will potentially be able to write:

<Button m={{ sm: 2, md: 1 }}>Hello World</Button> to have a button with a margin 16px on mobile and 8px on desktop.

Interested in learning more? You can give it a try 🎄.