Categories
Material UI

Material UI — Menu Customization

Material UI is a Material Design library made for React.

It’s a set of React components that have Material Design styles.

In this article, we’ll look at how to customize menus to Material UI.

Customized Menus

We can customize our menu with our styles.

For example, we can write:

import React from "react";
import { withStyles } from "@material-ui/core/styles";
import Button from "@material-ui/core/Button";
import Menu from "@material-ui/core/Menu";
import MenuItem from "@material-ui/core/MenuItem";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import ListItemText from "@material-ui/core/ListItemText";
import InboxIcon from "@material-ui/icons/MoveToInbox";

const StyledMenu = withStyles({
  paper: {
    border: "1px solid #d3d4d5"
  }
})(props => (
  <Menu
    elevation={0}
    getContentAnchorEl={null}
    anchorOrigin={{
      vertical: "bottom"
    }}
    transformOrigin={{
      vertical: "top"
    }}
    {...props}
  />
));

const StyledMenuItem = withStyles(theme => ({
  root: {
    "&:focus": {
      backgroundColor: theme.palette.primary.main,
      "& .MuiListItemIcon-root, & .MuiListItemText-primary": {
        color: theme.palette.common.white
      }
    }
  }
}))(MenuItem);

export default function App() {
  const [anchorEl, setAnchorEl] = React.useState(null);

  const handleClick = event => {
    setAnchorEl(event.currentTarget);
  };

  const handleClose = () => {
    setAnchorEl(null);
  };

  return (
    <div>
      <Button variant="contained" color="primary" onClick={handleClick}>
        Open Menu
      </Button>
      <StyledMenu open={Boolean(anchorEl)}>
        <StyledMenuItem onClick={handleClose}>
          <ListItemIcon>
            <InboxIcon fontSize="small" />
          </ListItemIcon>
          <ListItemText primary="home" />
        </StyledMenuItem>
      </StyledMenu>
    </div>
  );
}

to use the withStyles higher-order component to style the menu.

To style the menu items, we can style it with the withStyles higher-order component.

We set the color with one from the theme parameter.

Then we can use them all in our App component.

Max Height Menus

We can set the height of the Menu with the style property.

For example, we can write:

import React from "react";
import Button from "@material-ui/core/Button";
import Menu from "@material-ui/core/Menu";
import MenuItem from "@material-ui/core/MenuItem";

const options = ["apple", "orange", "grape", "banana", "pear", "mango"];

export default function App() {
  const [anchorEl, setAnchorEl] = React.useState(null);

  const handleClick = event => {
    setAnchorEl(event.currentTarget);
  };

  const handleClose = () => {
    setAnchorEl(null);
  };

  return (
    <div>
      <Button variant="contained" color="primary" onClick={handleClick}>
        Open Menu
      </Button>
      <Menu
        anchorEl={anchorEl}
        keepMounted
        open={Boolean(anchorEl)}
        onClose={handleClose}
        PaperProps={{
          style: {
            maxHeight: `200px`
          }
        }}
      >
        {options.map(option => (
          <MenuItem
            key={option}
            selected={option === "apple"}
            onClick={handleClose}
          >
            {option}
          </MenuItem>
        ))}
      </Menu>
    </div>
  );
}

We set the maxHeight property in the PaperProps to set the height of the menu.

Change Transition

We can add transitions when our menu is opening.

It takes a TransitionComponent prop to let us add the transition we want.

For example, we can write:

import React from "react";
import Button from "@material-ui/core/Button";
import Menu from "@material-ui/core/Menu";
import MenuItem from "@material-ui/core/MenuItem";
import Fade from "@material-ui/core/Fade";

export default function App() {
  const [anchorEl, setAnchorEl] = React.useState(null);
  const open = Boolean(anchorEl);

  const handleClick = event => {
    setAnchorEl(event.currentTarget);
  };

  const handleClose = () => {
    setAnchorEl(null);
  };

  return (
    <div>
      <Button onClick={handleClick}>Open</Button>
      <Menu
        anchorEl={anchorEl}
        keepMounted
        open={open}
        onClose={handleClose}
        TransitionComponent={Fade}
      >
        <MenuItem onClick={handleClose}>home</MenuItem>
        <MenuItem onClick={handleClose}>profile</MenuItem>
        <MenuItem onClick={handleClose}>logout</MenuItem>
      </Menu>
    </div>
  );
}

to add a fade transition when the menu is opening with the TransitionComponent prop set to Fade .

Context Menu

To add a context menu, we can listen to the onContextMenu prop.

Then we can show the context menu where we right-click by setting the mouse coordinates in the anchorPosition prop.

For instance, we can write:

import React from "react";
import Menu from "@material-ui/core/Menu";
import MenuItem from "@material-ui/core/MenuItem";
import Typography from "@material-ui/core/Typography";

const initialState = {
  mouseX: null,
  mouseY: null
};
export default function App() {
  const [state, setState] = React.useState(initialState);

  const handleClick = event => {
    event.preventDefault();
    setState({
      mouseX: event.clientX - 2,
      mouseY: event.clientY - 4
    });
  };

  const handleClose = () => {
    setState(initialState);
  };

  return (
    <div onContextMenu={handleClick} style={{ cursor: "context-menu" }}>
      <Typography>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ipsum
        purus, bibendum sit amet vulputate eget, porta semper ligula. Donec
        bibendum vulputate erat, ac fringilla mi finibus nec. Donec ac dolor sed
        dolor porttitor blandit vel vel purus. Fusce vel malesuada ligula. Nam
        quis vehicula ante, eu finibus est. Proin ullamcorper fermentum orci,
        quis finibus massa.
      </Typography>
      <Menu
        keepMounted
        open={state.mouseY !== null}
        onClose={handleClose}
        anchorReference="anchorPosition"
        anchorPosition={
          state.mouseY !== null && state.mouseX !== null
            ? { top: state.mouseY, left: state.mouseX }
            : undefined
        }
      >
        <MenuItem onClick={handleClose}>select</MenuItem>
        <MenuItem onClick={handleClose}>paste</MenuItem>
        <MenuItem onClick={handleClose}>copy</MenuItem>
        <MenuItem onClick={handleClose}>save</MenuItem>
      </Menu>
    </div>
  );
}

to add a div with some text.

And we add a context menu with the Menu component.

We add keepMounted to keep it in the DOM.

open is true when mouseY isn’t null .

It’s set when we right-click within the handleClick function.

anchorPosition lets us set the mousex and mouseY to make the menu open with the given mouse coordinates.

Conclusion

We can add menus with styles.

Also, we can add context menus.

Transitions can also be added to change effects when the menu opens.

Categories
Material UI

Material UI — Links and Menus

Material UI is a Material Design library made for React.

It’s a set of React components that have Material Design styles.

In this article, we’ll look at how to add links and menus to Material UI.

Simple Links

We can add links with the Link component.

For instance, we can write:

import React from "react";
import Link from "@material-ui/core/Link";

export default function App() {
  const preventDefault = event => event.preventDefault();

  return (
    <div>
      <Link href="#" onClick={preventDefault}>
        Link
      </Link>
    </div>
  );
}

We add a link with the href to go the URL we want when we click it.

onClick lets us pass in a click handler to change the behavior of the link.

We can also change the color to change the color of the link.

For example, we can write:

import React from "react";
import Link from "@material-ui/core/Link";

export default function App() {
  const preventDefault = event => event.preventDefault();

  return (
    <div>
      <Link href="#" onClick={preventDefault} color="primary">
        Link
      </Link>
    </div>
  );
}

We set the color to primary to make it purple.

Also, we can pass a value to the variant prop to change the styles:

import React from "react";
import Link from "@material-ui/core/Link";
import Typography from "@material-ui/core/Typography";

export default function App() {
  const preventDefault = event => event.preventDefault();

  return (
    <div>
      <Typography>
        <Link href="#" onClick={preventDefault} variant="inherit">
          Link
        </Link>
      </Typography>
    </div>
  );
}

Menus

We can add a menu with the Menu component.

Inside it, we can add items with the MenuItem components.

For example, we can write:

import React from "react";
import Button from "@material-ui/core/Button";
import Menu from "@material-ui/core/Menu";
import MenuItem from "@material-ui/core/MenuItem";

export default function App() {
  const [anchorEl, setAnchorEl] = React.useState(null);

  const handleClick = event => {
    setAnchorEl(event.currentTarget);
  };

  const handleClose = () => {
    setAnchorEl(null);
  };
  return (
    <div>
      <Button onClick={handleClick}>Open</Button>
      <Menu
        anchorEl={anchorEl}
        keepMounted
        open={Boolean(anchorEl)}
        onClose={handleClose}
      >
        <MenuItem onClick={handleClose}>home</MenuItem>
        <MenuItem onClick={handleClose}>profile</MenuItem>
        <MenuItem onClick={handleClose}>logout</MenuItem>
      </Menu>
    </div>
  );
}

to add a menu.

We have a Button that has the onClick prop set to the handleClick function.

It sets the anchor element to element so that we can open the menu.

We set the open prop of the menu to the anchor element.

The anchor element would be the button as indicated in the handleClick function.

This way, we can determine if the button is clicked and we can open the menu if it’s set.

To close the menu, we set the anchorEl to null so that open will have false passed in.

Selected Menus

We can keep a menu item selected.

To do that, we can set the selected prop to true if the item is selected.

For example, we can write:

import React from "react";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import Menu from "@material-ui/core/Menu";
import MenuItem from "@material-ui/core/MenuItem";

const options = ["apple", "orange", "grape"];

export default function App() {
  const [anchorEl, setAnchorEl] = React.useState(null);
  const [selectedIndex, setSelectedIndex] = React.useState(1);

  const handleClickListItem = event => {
    setAnchorEl(event.currentTarget);
  };

  const handleMenuItemClick = (event, index) => {
    setSelectedIndex(index);
    setAnchorEl(null);
  };

  const handleClose = () => {
    setAnchorEl(null);
  };

  return (
    <div>
      <List component="nav">
        <ListItem button onClick={handleClickListItem}>
          open
        </ListItem>
      </List>
      <Menu
        anchorEl={anchorEl}
        keepMounted
        open={Boolean(anchorEl)}
        onClose={handleClose}
      >
        {options.map((option, index) => (
          <MenuItem
            key={option}
            selected={index === selectedIndex}
            onClick={event => handleMenuItemClick(event, index)}
          >
            {option}
          </MenuItem>
        ))}
      </Menu>
    </div>
  );
}

to add a menu.

We keep the index of the selected item with the selectedIndex .

It’s set when we click on the MenuItem .

We have the selected prop that has a boolean expression to compare the index of the item against the selectedIndex value to determine which value is selected.

Customized Menu

We can create our own menu with the Popper , Paper and ClickAwayListener components.

For example, we can write:

import React from "react";
import Button from "@material-ui/core/Button";
import ClickAwayListener from "@material-ui/core/ClickAwayListener";
import Grow from "@material-ui/core/Grow";
import Paper from "@material-ui/core/Paper";
import Popper from "@material-ui/core/Popper";
import MenuItem from "@material-ui/core/MenuItem";
import MenuList from "@material-ui/core/MenuList";

export default function App() {
  const [open, setOpen] = React.useState(false);
  const anchorRef = React.useRef(null);

const handleToggle = () => {
    setOpen(prevOpen => !prevOpen);
  };

const handleClose = event => {
    if (anchorRef.current && anchorRef.current.contains(event.target)) {
      return;
    }

setOpen(false);
  };

function handleListKeyDown(event) {
    if (event.key === "Tab") {
      event.preventDefault();
      setOpen(false);
    }
  }

  const prevOpen = React.useRef(open);
  React.useEffect(() => {
    if (prevOpen.current === true && open === false) {
      anchorRef.current.focus();
    }

  prevOpen.current = open;
  }, [open]);

  return (
    <div>
      <Button ref={anchorRef} onClick={handleToggle}>
        menu
      </Button>
      <Popper open={open} anchorEl={anchorRef.current} transition disablePortal>
        {({ TransitionProps, placement }) => (
          <Grow
            {...TransitionProps}
            style={{
              transformOrigin:
                placement === "bottom" ? "center top" : "center bottom"
            }}
          >
            <Paper>
              <ClickAwayListener onClickAway={handleClose}>
                <MenuList autoFocusItem={open} onKeyDown={handleListKeyDown}>
                  <MenuItem onClick={handleClose}>home</MenuItem>
                  <MenuItem onClick={handleClose}>profile</MenuItem>
                  <MenuItem onClick={handleClose}>logout</MenuItem>
                </MenuList>
              </ClickAwayListener>
            </Paper>
          </Grow>
        )}
      </Popper>
    </div>
  );
}

We add the Button to toggle the menu.

The Popper has the actual menu.

The Grow component adds the transition for the menu with the TransitionProps .

We can set the transformOrigin to set how the menu is placed.

Paper has holds the ClickAwayListener so that the menu is closed when we click outside the menu.

MenuList has the menu entries.

handleClose sets the open state to false to close the menu.

We also have the handleListKeyDown function to handle Tab key presses.

We close the menu when it’s pressed.

Conclusion

We can add links and menus easily with the Link and Menu components.

Categories
Material UI

Material UI — Link and Accessible Tabs

UI is a Material Design library made for React.

It’s a set of React components that have Material Design styles.

In this article, we’ll look at how to add vertical tabs with Material UI.

Vertical Tabs

We can add vertical tabs with the orientation prop set to vertical .

For example, we can write:

import React from "react";
import Tabs from "@material-ui/core/Tabs";
import Tab from "@material-ui/core/Tab";
import Box from "@material-ui/core/Box";

function TabPanel(props) {
  const { children, value, index, ...other } = props;

  return <div {...other}>{value === index && <Box p={3}>{children}</Box>}</div>;
}

export default function App() {
  const [value, setValue] = React.useState(0);

  const handleChange = (event, newValue) => {
    setValue(newValue);
  };

  return (
    <div>
      <Tabs
        orientation="vertical"
        variant="scrollable"
        value={value}
        onChange={handleChange}
      >
        <Tab label="Item One" />
        <Tab label="Item Two" />
        <Tab label="Item Three" />
      </Tabs>
      <TabPanel value={value} index={0}>
        Item One
      </TabPanel>
      <TabPanel value={value} index={1}>
        Item Two
      </TabPanel>
      <TabPanel value={value} index={2}>
        Item Three
      </TabPanel>
    </div>
  );
}

to add tabs with content below it.

The tabs will be vertical since we set orientation to vertical .

Nav Tabs

We can also use nav links for tabs.

For example, we can write:

import React from "react";
import Tabs from "@material-ui/core/Tabs";
import Tab from "@material-ui/core/Tab";
import Box from "@material-ui/core/Box";
import AppBar from "@material-ui/core/AppBar";

function TabPanel(props) {
  const { children, value, index, ...other } = props;

return <div {...other}>{value === index && <Box p={3}>{children}</Box>}</div>;
}

function LinkTab(props) {
  return (
    <Tab
      component="a"
      onClick={event => {
        event.preventDefault();
      }}
      {...props}
    />
  );
}

export default function App() {
  const [value, setValue] = React.useState(0);

  const handleChange = (event, newValue) => {
    setValue(newValue);
  };

  return (
    <div>
      <AppBar position="static">
        <Tabs variant="fullWidth" value={value} onChange={handleChange}>
          <LinkTab label="Page One" href="/foo" />
          <LinkTab label="Page Two" href="/bar" />
          <LinkTab label="Page Three" href="/baz" />
        </Tabs>
      </AppBar>
      <TabPanel value={value} index={0}>
        Page One
      </TabPanel>
      <TabPanel value={value} index={1}>
        Page Two
      </TabPanel>
      <TabPanel value={value} index={2}>
        Page Three
      </TabPanel>
    </div>
  );
}

to add link tabs.

We have a LinkTab component that renders the Tab with the onClick prop set to a function that calls preventDefault so that we can navigate to the URL in the href prop.

Icon Tabs

Also, we can add icons to tabs.

We pass the icon into the icon prop of Tab to add an icon.

For example, we can write:

import React from "react";
import Tabs from "@material-ui/core/Tabs";
import Tab from "@material-ui/core/Tab";
import Paper from "@material-ui/core/Paper";
import PhoneIcon from "@material-ui/icons/Phone";
import FavoriteIcon from "@material-ui/icons/Favorite";
import AirplanemodeActiveIcon from "@material-ui/icons/AirplanemodeActive";

export default function App() {
  const [value, setValue] = React.useState(0);

  const handleChange = (event, newValue) => {
    setValue(newValue);
  };

  return (
    <div>
      <Paper square>
        <Tabs
          value={value}
          onChange={handleChange}
          variant="fullWidth"
          indicatorColor="primary"
          textColor="primary"
        >
          <Tab icon={<PhoneIcon />} />
          <Tab icon={<FavoriteIcon />} />
          <Tab icon={<AirplanemodeActiveIcon />} />
        </Tabs>
      </Paper>
    </div>
  );
}

to add icons to our tabs.

We pass the icon component as the value of the icon prop of the Tab .

Keyboard Navigation

We can add the selectionFollowsFocus prop to enable keyboard navigation./

For example, we can write:

import React from "react";
import Tabs from "@material-ui/core/Tabs";
import Tab from "@material-ui/core/Tab";
import Paper from "@material-ui/core/Paper";
import PhoneIcon from "@material-ui/icons/Phone";
import FavoriteIcon from "@material-ui/icons/Favorite";
import AirplanemodeActiveIcon from "@material-ui/icons/AirplanemodeActive";

export default function App() {
  const [value, setValue] = React.useState(0);

  const handleChange = (event, newValue) => {
    setValue(newValue);
  };

  return (
    <div>
      <Paper square>
        <Tabs
          selectionFollowsFocus
          value={value}
          onChange={handleChange}
          variant="fullWidth"
          indicatorColor="primary"
          textColor="primary"
        >
          <Tab icon={<PhoneIcon />} />
          <Tab icon={<FavoriteIcon />} />
          <Tab icon={<AirplanemodeActiveIcon />} />
        </Tabs>
      </Paper>
    </div>
  );
}

to enable keyboard navigation.

If we focus on the tabs, then we can navigate with the keyboard with it.

Conclusion

We can customize our tabs by making them vertical.

Also, we can add tabs that act as links.

And we can enable keyboard navigation.

Categories
Material UI

Material UI — Expansion Panels

Material UI is a Material Design library made for React.

It’s a set of React components that have Material Design styles.

In this article, we’ll look at how to add expansion panels with Material UI.

Expansion Panel

Expansion panels let us add boxes that can be expanded and collapsed.

To add a simple one, we can write:

import React from "react";
import ExpansionPanel from "@material-ui/core/ExpansionPanel";
import ExpansionPanelSummary from "@material-ui/core/ExpansionPanelSummary";
import ExpansionPanelDetails from "@material-ui/core/ExpansionPanelDetails";
import Typography from "@material-ui/core/Typography";
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";

export default function App() {
  return (
    <>
      <ExpansionPanel>
        <ExpansionPanelSummary
          expandIcon={<ExpandMoreIcon />}
          id="panel1-header"
        >
          <Typography>Expansion Panel 1</Typography>
        </ExpansionPanelSummary>
        <ExpansionPanelDetails>
          <Typography>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit.
          </Typography>
        </ExpansionPanelDetails>
      </ExpansionPanel>
      <ExpansionPanel>
        <ExpansionPanelSummary
          expandIcon={<ExpandMoreIcon />}
          id="panel2-header"
        >
          <Typography>Expansion Panel 2</Typography>
        </ExpansionPanelSummary>
        <ExpansionPanelDetails>
          <Typography>Sit amet blandit leo lobortis eget.</Typography>
        </ExpansionPanelDetails>
      </ExpansionPanel>
    </>
  );
}

to add 2 expansion panels with the ExpansionPanel s.

The expandIcon prop holds the icon that’s displayed for letting us expand the panel.

ExpansionPanelDetails has the content of the expansion panel.

ExpansionPanelSummary has the content of the heading.

Controlled Accordion

We can make it a controlled component buy passing in the expanded and onChange props to the ExpansionPanel .

For example, we can write:

import React from "react";
import ExpansionPanel from "@material-ui/core/ExpansionPanel";
import ExpansionPanelSummary from "@material-ui/core/ExpansionPanelSummary";
import ExpansionPanelDetails from "@material-ui/core/ExpansionPanelDetails";
import Typography from "@material-ui/core/Typography";
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";

export default function App() {
  const [expanded, setExpanded] = React.useState(false);

const handleChange = panel => (event, isExpanded) => {
    setExpanded(isExpanded ? panel : false);
  };

return (
    <>
      <ExpansionPanel
        expanded={expanded === "panel1"}
        onChange={handleChange("panel1")}
      >
        <ExpansionPanelSummary
          expandIcon={<ExpandMoreIcon />}
          id="panel1-header"
        >
          <Typography>Expansion Panel 1</Typography>
        </ExpansionPanelSummary>
        <ExpansionPanelDetails>
          <Typography>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit.
          </Typography>
        </ExpansionPanelDetails>
      </ExpansionPanel>
      <ExpansionPanel
        expanded={expanded === "panel2"}
        onChange={handleChange("panel2")}
      >
        <ExpansionPanelSummary
          expandIcon={<ExpandMoreIcon />}
          id="panel2-header"
        >
          <Typography>Expansion Panel 2</Typography>
        </ExpansionPanelSummary>
        <ExpansionPanelDetails>
          <Typography>Sit amet blandit leo lobortis eget.</Typography>
        </ExpansionPanelDetails>
      </ExpansionPanel>
    </>
  );
}

to make the expansion panels work together as an accordion.

We have the expanded prop that sets whether the expansion panel should be expanded.

onChange is a function that lets us set the panel to be expanded.

We set the panel name with the panel parameter of the handleChange function.

Customized Expansion Panels

We can change the styles of the expansion panel components with the withStyles higher order component.

For instance, we can write:

import React from "react";
import { withStyles } from "@material-ui/core/styles";
import MuiExpansionPanel from "@material-ui/core/ExpansionPanel";
import MuiExpansionPanelSummary from "@material-ui/core/ExpansionPanelSummary";
import MuiExpansionPanelDetails from "@material-ui/core/ExpansionPanelDetails";
import Typography from "@material-ui/core/Typography";

const ExpansionPanel = withStyles({
  root: {
    color: "blue"
  },
  expanded: {}
})(MuiExpansionPanel);

const ExpansionPanelSummary = withStyles({
  root: {
    backgroundColor: "pink"
  },
  content: {
    "&$expanded": {
      margin: "12px 0"
    }
  },
  expanded: {}
})(MuiExpansionPanelSummary);

const ExpansionPanelDetails = withStyles(theme => ({
  root: {
    padding: theme.spacing(2)
  }
}))(MuiExpansionPanelDetails);

export default function App() {
  const [expanded, setExpanded] = React.useState(false);

  const handleChange = panel => (event, isExpanded) => {
    setExpanded(isExpanded ? panel : false);
  };

  return (
    <>
      <ExpansionPanel
        expanded={expanded === "panel1"}
        onChange={handleChange("panel1")}
      >
        <ExpansionPanelSummary id="panel1-header">
          <Typography>Expansion Panel 1</Typography>
        </ExpansionPanelSummary>
        <ExpansionPanelDetails>
          <Typography>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit.
          </Typography>
        </ExpansionPanelDetails>
      </ExpansionPanel>
      <ExpansionPanel
        expanded={expanded === "panel2"}
        onChange={handleChange("panel2")}
      >
        <ExpansionPanelSummary id="panel2-header">
          <Typography>Expansion Panel 2</Typography>
        </ExpansionPanelSummary>
        <ExpansionPanelDetails>
          <Typography>Sit amet blandit leo lobortis eget.</Typography>
        </ExpansionPanelDetails>
      </ExpansionPanel>
    </>
  );
}

We pass in the MuiExpansionPanel , MuiExpansionPanelSummary and MuiExpansionPanelDetails into the function returned by the withStyles higher-order component.

We make the text color blue and the background of the summary pink.

If we use the component, then we’ll see those colors displayed.

Conclusion

We can create expansion panels that expands or collapses as we wish.

Also, we can change the styles of each component to fit our needs.

Categories
Material UI

Material UI — Expansion Panels Customization and Progress Spinner

Material UI is a Material Design library made for React.

It’s a set of React components that have Material Design styles.

In this article, we’ll look at how to customize expansion panels and add progress spinner with Material UI.

Additional Actions

We can add additional actions to expansion panels.

For example, we can write:

import React from "react";
import ExpansionPanel from "@material-ui/core/ExpansionPanel";
import ExpansionPanelSummary from "@material-ui/core/ExpansionPanelSummary";
import ExpansionPanelDetails from "@material-ui/core/ExpansionPanelDetails";
import Checkbox from "@material-ui/core/Checkbox";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import Typography from "@material-ui/core/Typography";
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";

export default function App() {
  return (
    <div>
      <ExpansionPanel>
        <ExpansionPanelSummary
          expandIcon={<ExpandMoreIcon />}
          id="additional-actions1-header"
        >
          <FormControlLabel
            onClick={event => event.stopPropagation()}
            onFocus={event => event.stopPropagation()}
            control={<Checkbox />}
            label="Lorem ipsum dolor sit amet"
          />
        </ExpansionPanelSummary>
        <ExpansionPanelDetails>
          <Typography>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit
          </Typography>
        </ExpansionPanelDetails>
      </ExpansionPanel>
      <ExpansionPanel>
        <ExpansionPanelSummary
          expandIcon={<ExpandMoreIcon />}
          id="additional-actions2-header"
        >
          <FormControlLabel
            onClick={event => event.stopPropagation()}
            onFocus={event => event.stopPropagation()}
            control={<Checkbox />}
            label="Praesent id erat pretium"
          />
        </ExpansionPanelSummary>
        <ExpansionPanelDetails>
          <Typography>
            Praesent id erat pretium, mollis turpis sit amet, vestibulum ipsum.
            Phasellus non mi eu velit lacinia consequat
          </Typography>
        </ExpansionPanelDetails>
      </ExpansionPanel>
    </div>
  );
}

to add an expansion panel with a checkmark beside the text in the heading.

We nested a ExpansionPanelSummary component to add a checkbox with the FormControlLabel and the Checkbox components.

We’ve to add event handlers for the onClick and onFocus props in the FormControlLabel s so that the click events of the checkboxes won’t propagate to the expansion panel summary.

Secondary Heading and Columns

We can add whatever we want into the headings and content.

So we can add secondary headings if we want.

To do that, we can write:

import React from "react";
import ExpansionPanel from "@material-ui/core/ExpansionPanel";
import ExpansionPanelDetails from "@material-ui/core/ExpansionPanelDetails";
import ExpansionPanelSummary from "@material-ui/core/ExpansionPanelSummary";
import ExpansionPanelActions from "@material-ui/core/ExpansionPanelActions";
import Typography from "@material-ui/core/Typography";
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
import Button from "@material-ui/core/Button";
import Divider from "@material-ui/core/Divider";
import { makeStyles } from "@material-ui/core/styles";

const useStyles = makeStyles(theme => ({
  column: {
    flexBasis: "33.33%"
  }
}));

export default function App() {
  const classes = useStyles();

  return (
    <div>
      <ExpansionPanel defaultExpanded>
        <ExpansionPanelSummary
          expandIcon={<ExpandMoreIcon />}
          id="panel1c-header"
        >
          <div className={classes.column}>
            <Typography>Fruits</Typography>
          </div>
          <div className={classes.column}>
            <Typography>choose a fruit</Typography>
          </div>
        </ExpansionPanelSummary>
        <ExpansionPanelDetails>
          <div>
            <Typography variant="caption">apple, orange</Typography>
          </div>
        </ExpansionPanelDetails>
        <Divider />
        <ExpansionPanelActions>
          <Button size="small">Cancel</Button>
          <Button size="small" color="primary">
            Save
          </Button>
        </ExpansionPanelActions>
      </ExpansionPanel>
    </div>
  );
}

We add some text that is divided into columns.

The className are set so that we can see stuff side by side.

Also, we used the ExpansionPanelActions component to add some buttons into its own container.

The Divider is displayed as a line between the ExpansionPanelDetails and ExpansionPanelActions .

Progress Indicators

To show that something is loading, we can add a progress indicator to our app.

For example, we can use the CircularProgress component to show the loading spinner.

We can write:

import React from "react";
import CircularProgress from "@material-ui/core/CircularProgress";

export default function App() {
  return (
    <div>
      <CircularProgress />
    </div>
  );
}

to add a circular spinner.

We can change the color with the color :

import React from "react";
import CircularProgress from "@material-ui/core/CircularProgress";

export default function App() {
  return (
    <div>
      <CircularProgress color="secondary" />
    </div>
  );
}

Circular Determinate

We can display a circular progress spinner to display the spinner only when something is loading.

For instance, we can write:

import React from "react";
import CircularProgress from "@material-ui/core/CircularProgress";

export default function App() {
  const [progress, setProgress] = React.useState(0);

  React.useEffect(() => {
    const timer = setInterval(() => {
      setProgress(prevProgress =>
        prevProgress >= 100 ? 0 : prevProgress + 10
      );
    }, 800);

    return () => {
      clearInterval(timer);
    };
  }, []);

  return (
    <div>
      <CircularProgress variant="static" value={progress} />
    </div>
  );
}

We add the CircularProgress component with the variant set to static to make it static.

This lets us update the spinner display when the progress state updates.

Conclusion

We can customize our expansion panels with the content that we want.

Also, we can add a progress spinner that displays as an uncontrolled component.

Or we can animate it according to the progress of something.

The styling of everything can be customized.