
¿Eh? ¿Otra biblioteca más? ¿Qué pasa con Bootstrap? ¿Y por qué no la v0.20?
¡Grandes preguntas! Comencemos con una breve introducción. En pocas palabras, Material-UI es un proyecto de código abierto que presenta componentes React que implementan Material Design de Google.
Se inició en 2014, poco después de que React se hiciera público, y desde entonces ha ganado popularidad. Con más de 35,000 estrellas en GitHub, Material-UI es una de las mejores bibliotecas de interfaz de usuario para React.
Sin embargo, su éxito no estuvo exento de desafíos. Diseñado con MENOS, Material-UI v0.x era propenso a los errores comunes de CSS, como el alcance global, que conducen al proyecto en la trayectoria de CSS-in-JS. Así next
surgió en 2016.
El viaje hacia un mejor estilo, como dice Olivier Tassinari, comenzó con los estilos en línea, pero su rendimiento subóptimo y su soporte limitado de funciones (piense en pseudo selectores o consultas de medios), finalmente hizo que el equipo pasara a JSS. Y vaya, hicieron una elección inteligente.
¿Cuál es el bombo publicitario con la versión v1?
Es malo. No solo aborda los problemas inherentes a LESS, sino que también desbloquea un montón de características fabulosas, que incluyen
- estilos dinámicos generados en tiempo de ejecución
- temas anidados con anulaciones intuitivas
- tiempo de carga reducido con división de código
Y muchos más. La biblioteca también es lo suficientemente madura para ser utilizada en producción. Tanto es así que el equipo sugiere la versión 1 para todos los proyectos nuevos en el futuro.
Muy bien, ¿vamos a crear una aplicación o qué?
¡Me alegro de que lo hayas preguntado! Para esta demostración, crearemos una aplicación de fitness sencilla. De todos modos, todo el mundo está aburrido de las aplicaciones de tareas pendientes, ¿verdad?
Leer es genial y todo eso, ¡pero ver a menudo es más divertido! Echa un vistazo a esta lista de reproducción que hice en YouTube si quieres crear una aplicación más avanzada.
Ok, me convenciste. ¿Cómo empiezo?
Primero arrancaremos nuestra aplicación con create-react-app
create-react-app mui-fitnesscd mui-fitnesscode .
¿Y qué hay de Material-UI?
Si tiene hilo, la instalación es tan simple como
yarn add @material-ui/core
De lo contrario, con npm
npm i @material-ui/core
No hace mucho tiempo, especificábamos la @next
etiqueta para incorporar el último prelanzamiento (por ejemplo, podría haber parecido v1.0.0-beta.47
). Ahora que tanto v1 como v0.x están bajo el material-ui
alcance, debemos hacer referencia al núcleo de la biblioteca /core
para apuntar a la última versión. ¡No te pierdas la última parte o terminarás con una 0.20
dependencia estable !
Espera, ¿es eso realmente?
¡Casi! Una última cosa son las fuentes. Iremos con la fuente Roboto recomendada del CDN de Google:
Alternativamente, puede extraerlo de NPM con
yarn add typeface-roboto# or npm i typeface-roboto
en cuyo caso, deberá tener una importación en la raíz de su proyecto
// Make sure you only load 300, 400, & 500 font weights though!import 'typeface-roboto'
¡Hecho! ¿Que hago después?
Bueno, refactoricemos nuestro App.js
componente antes de continuar.
import React, { Component } from 'react'
export default class App extends Component { state = { exercises: [], title: '' }
render() { return Exercises
}}
¿Y por qué no limpiar index.js
mientras estamos en eso?
import React from 'react'import { render } from 'react-dom'import App from './App'
render(, document.getElementById('root'))
Siéntase libre de eliminar los archivos restantes debajo src
, ya que no los necesitaremos.
¿Dónde entra Material-UI?
Muy bien, es hora de verlo en acción. Cambiemos lo feo h1
por un hermoso Typography
título:
import Typography from '@material-ui/core/Typography'
...
render() { return ( Exercises ) }}
Tenga en cuenta que desde v1.0.0-rc.0, MUI se movió
@material-ui/core
y la ruta de importación se aplanó. Este fue el último cambio importante en el prelanzamiento.
Luego sigue adelante y corre yarn start
para ver la magia.

¡Hemos tenido un buen comienzo! Typography
El componente viene con un conjunto predefinido de tamaños de letra. Otros variant
s incluyen body1
, title
, display2
, y así sucesivamente. Entre otros accesorios incorporados están los align
que usamos aquí para centrar el texto horizontalmente y gutterBottom
que agregan un margen inferior.
Why don’t we expand this to a form, so we can create our own exercises? We’ll start with a TextField
and bind it to the title
on the state
import Typography from '@material-ui/core/Typography'import TextField from '@material-ui/core/TextField'
...
handleChange = ({ target: { name, value } }) => this.setState({ [name]: value })
render() { const { title } = this.state return ( ... ) }}
Of course, we’d need to make React happy by wrapping Typography
and form
with a parent element. What could be a better opportunity for a paper-sheet card-like background? Let’s reach out to Paper
then
import Paper from '@material-ui/core/Paper'
...
render() { const { title } = this.state return ... } }}
It’s also about time to start using named imports (assuming our Webpack setup allows for tree shaking):
import { Paper, Typography, TextField } from '@material-ui/core'
Sweet! And what good is a form without the submit button? Button
s are a staple component in Material-UI; you’ll see them everywhere. For instance,
import { Paper, Typography, TextField, Button } from '@material-ui/core'... Create }}
It should read well. type
is a regular React prop, color
and variant
are Material-UI-specific, and make up a rectangle-shaped button. Another variant would be fab
for a floating button, for example.

It doesn’t do much though. We’ll have to intercept the form submit event
return ... ... }}
and then handle it with
handleCreate = e => { e.preventDefault()
if (this.state.title) { this.setState(({ exercises, title }) => ({ exercises: [ ...exercises, { title, id: Date.now() } ], title: '' })) } }
Whoa! What’s that cryptic code all about? Very quickly, we
- Prevent the default page reload
- Check if the
title
field is non-empty - Set the state with an updater function to mitigate async updates
- Destructure
exercises
andtitle
off theprevState
object - Spread out the
exercises
on the next state with a new exercise object - Reset the
title
to clear out the input field
Guess I should have mentioned that I’m in love with ES6 too. Aren’t we all?
But how do we list them?
Now is the right time to. Is there a list component? Of course, you silly goose!
Inside a List
, we’ll loop through our exercises
and return a ListItem
with some ListItemText
for each
import { List, ListItem, ListItemText } from '@material-ui/core'
...
render() { const { title, exercises } = this.state return ... {exercises.map(({ id, title }) => )} }}
Let’s also hard-code a few initial exercises to get something on the screen. You guessed it, the trinity of all weight lifting workouts, ladies and gents:
state = { exercises: [ { id: 1, title: 'Bench Press' }, { id: 2, title: 'Deadlift' }, { id: 3, title: 'Squats' } ], title: '' }

Last but not least, our users are likely to make typos, so we better add a delete button next to each exercise, so they could remove entries they no longer want in their list.
We can use ListItemSecondaryAction
to do exactly that. Placed on the far right of the list item, it can hold a secondary control element, such as an IconButton
with some action
import { /*...*/, ListItemSecondaryAction, IconButton} from '@material-ui/core'
...
this.handleDelete(id)} > {/* ??? */}
...
And let’s not forget the delete handler as well:
handleDelete = id => this.setState(({ exercises }) => ({ exercises: exercises.filter(ex => ex.id !== id) }))
which will simply filter our exercises down to those that don’t match the id
of the one that needs to be removed.
Can we have a trash bin icon inside the button?
Yes, that would be great! Though you could use Material Icons from Google’s CDN directly with either Icon
or SvgIcon
components, it’s often preferable to go with a ready-made preset.
Luckily, there’s a Material-UI package for those
yarn add @material-ui/icons# or npm i @material-ui/icons
It exports 900+ official material icons as React components, and the icon names are nearly identical, as you’ll see below.
Let’s say we wanted to add a trash icon. We’d first head over to material.io/icons to find out its precise name

Then, we turn that name into PascalCase in our import path
import Delete from '@material-ui/icons/Delete'
Just like with Material-UI components, if your setup has tree-shaking enabled, you could shorten the import to
import { Delete } from '@material-ui/icons'
which is especially useful when importing several icons at once.
Now that we have our trash icon, let’s display it inside our delete button
this.handleDelete(id)}>

How can I make the form look less ugly?
Ah, styling. I thought you’d never ask! A gentle touch of CSS wouldn’t hurt. So then, do we import an external stylesheet with global styles? Or, perhaps, use CSS modules and assign scoped class names to our elements? Not quite.
Under the hood, Material-UI forks a CSS-in-JS library known as react-jss.
It’s a React integration of the JSS library by the same author, Oleg Isonen. Remember we touched on it in the beginning? Its basic idea is to enable you to define styles in JavaScript. What makes JSS stand out among other libs though, is its support for SSR, small bundle size, and rich plugin support.
¡Hagamos un intento! En nuestro App
componente, cree un objeto de estilos como lo haría con los estilos en línea. Luego, crea una clave, por ejemplo root
, que se refiera al Paper
elemento raíz , y escribe algunos estilos en camelCase
const styles = { root: { margin: 20, padding: 20, maxWidth: 400 }}
A continuación, importe withStyles
HOC desdematerial-ui
import { withStyles } from '@material-ui/core/styles'
y envuelve el App
componente con él, pasando el styles
objeto como arg
export default withStyles(styles)( class App extends Component { ... })
Tenga en cuenta que también puede utilizar
withStyles
HOC como decorador. Tenga en cuenta que create-react-react no admite decoradores listos para usar, por lo que si insiste en usarlos, deberá expulsarlos o bifurcarlos para modificar la configuración.
Esto inyectará un classes
accesorio que App
contiene un nombre de clase generado dinámicamente para nuestro root
elemento

The class name is guaranteed to be unique, and it will often be shortened in a production build. We then assign it to Paper
via className
attribute
render() { const { title, exercises } = this.state const { classes } = this.props
return ... }

How does this magic work? Turns out, withStyles
is responsible for the dirty work. Behind the scenes, it injected an array of styles into the DOM under
o the
with dev tools

You could also see other style
tags related to native components, such as MuiListItem
for the ListItem
component we imported earlier. Those are auto-injected on demand, for each given UI element that you import.
That means that Material-UI will never load any styles for the components that we don’t use. Hence, increased performance and faster load times. This is very different from Bootstrap, which requires loading the entire monolithic CSS bundle, whether you happen to use its vast assortment of classes or not.
Let’s also style the form so it looks neat
const styles = { root: { ... }, form: { display: 'flex', alignItems: 'baseline', justifyContent: 'space-evenly' }}
This will make the text field and the button nicely spaced out. Feel free to refer to align-items and justify-content at CSS-Tricks should you need any further clarification on the Flexbox layout.

Sure, but what’s up with theming then?
withStyles
HOC is tailored for customizing a one-off component, but it’s not suited for application-wide overwrites. Whenever you need to apply global changes to all components in Material-UI, your first instinct would be to reach out to the theme
object.
Themes are designed to control colors, spacing, shadows, and other style attributes of your UI elements. Material-UI comes with built-in light and dark theme types, light being the default.
If we turn our styles
into an anonymous function, it will receive the theme
object as an arg, so we can inspect it
const styles = theme => console.log(theme) || ({ root: ..., form: ...})

The way you customize your theme is through configuration variables, like palette
, type
, typography
, etc. To have a closer look at all the nested properties and options, visit the Default Theme section of the Material-UI docs.
Let’s say we wanted to change the primary color from blue
to orange
. First off, we need to create a theme with createMuiTheme
helper in index.js
import { createMuiTheme } from '@material-ui/core/styles'
const theme = createMuiTheme({ /* config */ })
In Material-UI, colors are defined under the palette
property of theme
. The color palette is subdivided into intentions which include primary
, secondary
, and error
. To customize an intention, you can simply provide a color object
import { orange } from '@material-ui/core/colors'
const theme = createMuiTheme({ palette: { primary: orange }})
When applied, the color will then be calculated for light
, main
, dark
, and contrastText
variations. For more granular control though, you could pass in a plain object with any of those four keys
const theme = createMuiTheme({ palette: { primary: { light: orange[200] // same as '#FFCC80', main: '#FB8C00', // same as orange[600] dark: '#EF6C00', contrastText: 'rgb(0,0,0)' } }})
As you can see, individual colors can be expressed as both a hex or rgba string (#FFCC80
) and a hue/shade pair (orange[200]
).

Creating a theme on its own won’t suffice. To overwrite the default theme, we would need to position MuiThemeProvider
at the root of our app and pass our custom theme
as a prop
import { /*...*/, MuiThemeProvider } from '@material-ui/core/styles'
const theme = createMuiTheme({ palette: { primary: orange }})
render( , document.getElementById('root'))
MuiThemeProvider
will then pass down the theme
to all its child elements through React context.

Though it may seem like a lot of work to change a color, keep in mind that this overwrite will propagate to all components nested under the provider. And apart from colors, we can now fine-tune viewport sizes, spacing, opacity, and many other parameters.
Utilizing config variables when styling your components will aid with consistency and symmetry in your app’s UI. For example, instead of hard-coding magic values for margin
and padding
on our Paper
component, we could instead rely on the spacing unit off the theme
const styles = ({ spacing: { unit } }) => ({ root: { margin: unit, padding: unit * 3, maxWidth: 400 }, form: ...}
theme.spacing.unit
comes at 8px
by default, but if it’s used uniformly across the app, when we need to update its value, rather than scavenging across the entire codebase, we only need to change it in one place, that is, in our options object that we pass to createMuiTheme
.
Theme variables are plentiful, and if you run into a use case that’s not covered by the built-in theme object, you could always define your own custom vars. Here’s a slightly modified version of our fitness app that showcases color palette, theme type, and spacing unit options

Note that the example above is only a demo. It re-creates a new theme each time an option changes, which leads to a new CSS object being re-computed and re-injected into the DOM. Most often than not, your theme config will remain static.
There are far more interesting features that we haven’t covered. For example, Material-UI comes with an opt-in CssBaseline
component that applies cross-browser normalizations, such as resetting margins or font family (very much like normalize.css does).
As far as components go, we have our standard Grid
with a 12-column layout and five viewports (xs
, sm
, md
, lg
, and xl
). We’ve also got familiar components like Dialog
, Menu
, and Tabs
, as well as elements, such as Chip
and Tooltip
. Indeed, there’s a whole slue of others, and fortunately, they are all very-well documented with runnable demo code from CodeSandbox

Aside from that, Material-UI Next also works with SSR, if you’re into that. Besides, although it comes with JSS out of the box, it can me made to work with just about any other library, like Styled Components, or even raw CSS.
Be sure to check out the official docs for more info.
I hope you found this read useful! And if you like it so much that you are excited to learn more about Material-UI or React, then check out my YouTube channel maybe?
Thanks for stopping by! And big thanks to the team over at Call-Em-All and all the backers who helped to build this awesome library ❤️
Cheers,
Alex