Material-UI

Getting started with Material-UI

Material-UI

by John Vincent


Posted on May 28, 2018


This article describes how to configure Material-UI and some basic usage.

General

Material-UI

Typography

Font Icons

Github

Releases

Material-UI is a fast moving ecosystem. For release information

  • go to Github
  • Releases
  • Scan through the releases, there are so many.

Installation

Material-UI Installation

Install the package:

npm install --save material-ui@next

Handle Roboto Font

<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500">

or, not recommended

npm install typeface-roboto --save

and

import 'typeface-roboto'

Handle Font Icons

<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">

SVG Icons

npm install --save material-ui-icons

Quick Start

npm install --save material-ui@next

index.html

<!DOCTYPE html>
<html>

<head>
    <title>My App</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700" rel="stylesheet">
</head>

<body>
    <div id="app"></div>
</body>

</html>
import React from 'react';
import { render } from 'react-dom';
import Button from 'material-ui/Button';

function App() {
  return (
    <Button variant="raised" color="primary">
      Hello World
    </Button>
  );
}

render(<App />, document.getElementById('app'));

withStyles

import { withStyles } from 'material-ui/styles';

const styles = theme => ({
    container: {
        display: 'flex',
        flexDirection: 'column'
    },
    card: {
        width: '300px',
        // maxWidth: 400,
        margin: '15px',
        position: 'relative'
    }
});

render() {
    const { classes } = this.props;

<Icon name="register" css={classes.drawerIcon} />

HomeAppBar.propTypes = {
    classes: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
};

export default withStyles(styles)(HomeAppBar);
export default compose(withStyles(styles), connect(mapStateToProps))(HomeAppBar);

withStyles, external Styles

import { withStyles } from 'material-ui/styles';

import HomeLayoutStyles from './HomeLayoutStyles';

render() {
    const { classes } = this.props;

<Icon name="register" css={classes.drawerIcon} />

HomeAppBar.propTypes = {
    classes: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
};

export default withStyles(HomeLayoutStyles)(HomeAppBar);
export default compose(withStyles(HomeLayoutStyles), connect(mapStateToProps))(HomeAppBar);

withTheme

render() {
    const { theme } = this.props;
        
TaskDialog.propTypes = {
    theme: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
};

export default withStyles(styles, { withTheme: true })(HomeAppBar);
export default compose(withStyles(HomeLayoutStyles, { withTheme: true }), connect(mapStateToProps))(HomeLayout);

withWidth

import { compose } from 'redux';

import withWidth from 'material-ui/utils/withWidth';

<Typography variant="subheading">Current width: {this.props.width}</Typography>

HomeLayout.propTypes = {
    width: PropTypes.string.isRequired
};

export default compose(withWidth(), withStyles(HomeLayoutStyles, { withTheme: true }))(HomeLayout);

withRouter

Access the location, history and match objects:

import { withRouter } from 'react-router-dom';

export default withRouter(compose(withStyles(SidebarStyles), connect(mapStateToProps, mapDispatchToProps))(Sidebar));

render() {
    const { classes, location, history, match } = this.props;
    const pathname = location && location.pathname ? location.pathname : '';

Sidebar.propTypes = {
    location: PropTypes.shape({
        pathname: PropTypes.string.isRequired
    }).isRequired
};

Use the history object:

handleLink = () => {
    const { id } = this.props;
    this.props.history.push(`/goal/${id}`);
    this.handleClose();
};

Use the match object:

const { param } = this.props.match.params;

MemberMain.propTypes = {
    match: matchType.isRequired, // eslint-disable-line react/no-typos
};

export const matchType = PropTypes.shape({
    match: PropTypes.any
});

or more exactly:

export const matchType = PropTypes.shape({
    isExact: PropTypes.bool.isRequired,
    path: PropTypes.string.isRequired,
    url: PropTypes.string.isRequired,
    params: PropTypes.any.isRequired
});

With Redux

Use an action:

import { connect } from 'react-redux';
import { bindActionCreators, compose } from 'redux';

import * as actions from '../../actions/';

this.props.actions.moveUserObject(from, to, insertBefore);

const mapDispatchToProps = dispatch => ({
    actions: bindActionCreators(actions, dispatch)
});

export default connect(null, mapDispatchToProps)(ListTask);

Get object from redux:

render() {
    const { goals } = this.props;

HomeMain.propTypes = {
    goals: goalsType.isRequired, // eslint-disable-line react/no-typos
};

const mapStateToProps = state => ({
    goals: state.dataReducer.goals
});

const mapDispatchToProps = dispatch => ({
    actions: bindActionCreators(actions, dispatch)
});

export default compose(connect(mapStateToProps, mapDispatchToProps))(HomeMain);

Use withStyles

export default compose(withStyles(styles), connect(null, mapDispatchToProps))(ProjectCard);

Use withStyles and withTheme

export default compose(withStyles(styles, { withTheme: true }), connect(mapStateToProps, mapDispatchToProps))(
    TaskDialog
);

classnames

General form

import classNames from 'classnames';

<Tag classname=classNames('some className', {
    addThisClassToo: someExpression,
    addThisClassToo: someExpression,
    });
...
</Tag>
<IconButton
    className={classNames(classes.expand, classes.smallIcon, {
        [classes.expandOpen]: this.state.expanded
    })}
    onClick={() => this.toggleTasks()}
    aria-expanded={this.state.expanded}
    aria-label="Show more"
>
    {this.state.listTasks ? <ExpandLessIcon /> : <ExpandMoreIcon />}
</IconButton>
<AppBar
className={classNames(classes.appBar, {
    [classes.appBarShift]: open,
    [classes[`appBarShift-${anchor}`]]: open
    })}
<IconButton
    color="inherit"
    aria-label="open drawer"
    onClick={this.handleDrawerOpen}
    className={classNames(classes.menuButton, open && classes.hide)}
>
    <MenuIcon />
</IconButton>   
<Toolbar
    className={classNames(classes.root, {
        [classes.highlight]: numSelected > 0
    })}
>
const styles = theme => ({
    margin: {
        margin: theme.spacing.unit
    },
    textField: {
        flexBasis: 200
    }
});

className={classNames(classes.margin, classes.textField)}