Building Web Page Layout with Flexbox and Grid in React and Material-UI V5
Rany ElHousieny, PhD???
Senior Software Engineering Manager (EX-Microsoft) | Generative AI Leader @ Clearwater Analytics | Generative AI, Conversational AI Solutions Architect
Introduction:
Web page layout is a critical aspect of web development, as it determines how the content is presented to users. Traditionally, developers used CSS floats and positioning to create layouts, which could often be complex and hard to maintain. However, with the advent of modern CSS features like Flexbox and Grid, creating responsive and dynamic layouts has become much more straightforward.
In this article, we will explore how to use Flexbox and Grid in the context of React and Material-UI to create flexible and responsive web page layouts. We will provide simple code examples that you can visualize and experiment with on CodeSandbox .
Understanding Flexbox Terminology
Understanding the concepts of the main axis, cross axis, flex container, and flex items is crucial when working with Flexbox. Let's delve deeper into each of these terms:
Main Axis:
The main axis is the primary axis along which flex items are laid out within a flex container. It can either be horizontal (left-to-right) or vertical (top-to-bottom), depending on the value of the flex-direction property set on the flex container.
In essence, the main axis defines the direction in which flex items are placed side by side or on top of each other.
The main axis and cross axis change depending on whether the flex-direction is set to row or column. Let's clarify the main axis for both cases:
Main Axis for flex-direction: row;:
Main Axis for flex-direction: column;:
In summary, the main axis direction changes based on the flex-direction property. When flex-direction is row, the main axis is horizontal, and when flex-direction is column, the main axis is vertical. The cross axis is always perpendicular to the main axis, running in the opposite direction.
Cross Axis:
The cross axis is the perpendicular axis to the main axis. It runs perpendicular to the direction of the main axis and is used to control the alignment of flex items along that axis.
The cross axis complements the main axis and is responsible for aligning flex items within the flex container in the direction perpendicular to the main axis.
Flex Container:
The flex container is an HTML element (typically a div) that is set to display its children as flex items. By setting the container to display: flex; or display: inline-flex;, you create a flex container, and its direct children become flex items.
The flex container can have various properties and settings that affect how its flex items are laid out. Some of the essential properties that can be applied to the flex container include:
Hands-On Example for Flex Container
Let's practice what we learned through a Hands-On Example
Prerequisites:
Before getting started, make sure you have a basic understanding of React and Material-UI. Familiarity with HTML and CSS will also be beneficial. The following Articles can
Getting Started:
To follow along, create a new React project or use an existing one. You can also use CodeSandbox, an online code editor for web development projects. If you're using CodeSandbox, go to https://codesandbox.io/ and create a new React template.
Step 1: Set up Material-UI in the project
In your React project or CodeSandbox, install the Material-UI library:
npm install @mui/material @emotion/react @emotion/styled
You can also add it to dependencies on the Sandbox
Step 2: Create a basic layout using Flexbox
In this step, we'll create a simple header, content, and footer layout using Flexbox.
import React from 'react';
import { AppBar, Toolbar, Typography, Container } from '@mui/material';
const App = () => {
? return (
? ? <div>
? ? ? <AppBar position="static">
? ? ? ? <Toolbar>
? ? ? ? ? <Typography variant="h6">My App</Typography>
? ? ? ? </Toolbar>
? ? ? </AppBar>
? ? ? <Container
? ? ? ? sx={{
? ? ? ? ? display: 'flex',
? ? ? ? ? flexDirection: 'column',
? ? ? ? ? justifyContent: 'center',
? ? ? ? ? alignItems: 'center',
? ? ? ? ? height: '20vh',
? ? ? ? }}
? ? ? >
? ? ? ? <Typography variant="h4">Welcome to My App!</Typography>
? ? ? ? <Typography variant="body1">
? ? ? ? ? This is the main content of the page.
? ? ? ? </Typography>
? ? ? </Container>
? ? ? <footer
? ? ? ? style={{
? ? ? ? ? display: 'flex',
? ? ? ? ? justifyContent: 'center',
? ? ? ? ? alignItems: 'center',
? ? ? ? ? height: '10vh',
? ? ? ? ? backgroundColor: '#f0f0f0',
? ? ? ? }}
? ? ? >
? ? ? ? <Typography variant="body2">? {new Date().getFullYear()} My App</Typography>
? ? ? </footer>
? ? </div>
? );
};
export default App;
Explanation of the Code:
Importing Required Components:
In the code, we start by importing the necessary components from Material-UI. These components are crucial for building our layout, including the AppBar, Toolbar, Typography, Container, Grid, and Paper.
Flexbox-based Layout:
In the first part of the code, we create a basic Flexbox-based layout. Flexbox is a one-dimensional layout model that allows us to distribute items within a container along a single axis (row or column). We use the Container component as the main container for our layout.
The result is a layout with a centered header, centered content in the middle, and a centered footer at the bottom.
In the context of CSS Flexbox, both justifyContent and alignItems are properties used to control the alignment and distribution of flex items within a flex container. However, they work along different axes, leading to different positioning effects:
justifyContent:
The justifyContent property is used to align flex items along the main axis of the flex container. The main axis is determined by the flexDirection property, which can be set to either 'row' (left-to-right) or 'column' (top-to-bottom).
Available values for justifyContent include:
In the first example, justifyContent: 'center' centers the flex items vertically along the main axis (column direction), as the flexDirection is set to 'column'. This centers the text elements within the Container component vertically.
alignItems:
The alignItems property is used to align flex items along the cross axis of the flex container. The cross axis is the perpendicular axis to the main axis. So, if the flexDirection is set to 'row', the cross axis runs vertically, and if it's set to 'column', the cross axis runs horizontally.
Available values for alignItems include:
In the provided example, alignItems: 'center' centers the flex items horizontally along the cross axis (column direction), as the flexDirection is set to 'column'. This centers the text elements within the Container component horizontally.
In summary, justifyContent controls the alignment of flex items along the main axis, and alignItems controls the alignment along the cross axis. They work together to position flex items within a flex container effectively.
===========
Flex Items:
Flex items are the direct children of a flex container. These items are laid out along the main axis of the flex container and are aligned based on the properties set on the flex container.
Each flex item can have its own set of properties to control its behavior, such as:
By default, flex items will try to stretch to fill the entire cross axis of the flex container unless specified otherwise.
Hands-On Example for Flex Container
Let's update the previous example to demonstrate how to manage Flex Items (children) within the Flex Container. We'll use Flexbox properties on individual Flex Items to control their layout and sizing. For this example, we'll use flex and order properties.
import React from 'react';
import { AppBar, Toolbar, Typography, Container } from '@mui/material';
const App = () => {
? return (
? ? <div>
? ? ? <AppBar position="static">
? ? ? ? <Toolbar>
? ? ? ? ? <Typography variant="h6">My App</Typography>
? ? ? ? </Toolbar>
? ? ? </AppBar>
? ? ? <Container
? ? ? ? sx={{
? ? ? ? ? display: 'flex',
? ? ? ? ? flexDirection: 'row', // Main axis runs horizontally
? ? ? ? ? justifyContent: 'center',
? ? ? ? ? alignItems: 'center',
? ? ? ? ? height: '90vh',
? ? ? ? }}
? ? ? >
? ? ? ? <Typography
? ? ? ? ? variant="h4"
? ? ? ? ? style={{ flex: 1, order: 2 }}
? ? ? ? >
? ? ? ? ? Welcome to My App!
? ? ? ? </Typography>
? ? ? ? <Typography
? ? ? ? ? variant="body1"
? ? ? ? ? style={{ flex: 1, order: 1 }}
? ? ? ? >
? ? ? ? ? This is the main content of the page.
? ? ? ? </Typography>
? ? ? </Container>
? ? ? <footer
? ? ? ? style={{
? ? ? ? ? display: 'flex',
? ? ? ? ? justifyContent: 'center',
? ? ? ? ? alignItems: 'center',
? ? ? ? ? height: '10vh',
? ? ? ? ? backgroundColor: '#f0f0f0',
? ? ? ? }}
? ? ? >
? ? ? ? <Typography variant="body2">? {new Date().getFullYear()} My App</Typography>
? ? ? </footer>
? ? </div>
? );
};
export default App;
Explanation:
In this updated example, we have made the following changes to demonstrate Flex Item management:
flex: 1 for Flex Items:
We use the flex property on each Typography element to make them flexible and occupy the available space along the main axis. Setting flex: 1 on both elements makes them share the available horizontal space equally.
order property for Reordering Flex Items:
We use the order property to change the order in which the Typography elements are displayed. By default, Flex Items are displayed in the order they appear in the DOM. However, we can change this order using the order property.
领英推荐
The result is a Flexbox layout where the "Welcome to My App!" text appears above the "This is the main content of the page." text, and both items share the available horizontal space equally. The header and footer remain unchanged, as they are not part of the Flex Container.
Let's expand the previous example to demonstrate various Flex Item options using Material-UI v5 and the sx prop. We'll use different values for the flex and order properties to showcase different layouts within the Flex Container.
import React from 'react';
import { AppBar, Toolbar, Typography, Container } from '@mui/material';
const App = () => {
? return (
? ? <div>
? ? ? <AppBar position="static">
? ? ? ? <Toolbar>
? ? ? ? ? <Typography variant="h6">My App</Typography>
? ? ? ? </Toolbar>
? ? ? </AppBar>
? ? ? <Container
? ? ? ? sx={{
? ? ? ? ? display: 'flex',
? ? ? ? ? flexDirection: 'column', // Main axis runs vertically
? ? ? ? ? justifyContent: 'center',
? ? ? ? ? alignItems: 'center',
? ? ? ? ? height: '90vh',
? ? ? ? }}
? ? ? >
? ? ? ? <Typography
? ? ? ? ? variant="h4"
? ? ? ? ? sx={{ flex: 1, order: 2, bgcolor: 'primary.main', color: 'white', p: 2 }}
? ? ? ? >
? ? ? ? ? Welcome to My App! (Order: 2)
? ? ? ? </Typography>
? ? ? ? <Typography
? ? ? ? ? variant="body1"
? ? ? ? ? sx={{ flex: 2, order: 1, bgcolor: 'secondary.main', color: 'white', p: 2 }}
? ? ? ? >
? ? ? ? ? This is the main content of the page. (Order: 1)
? ? ? ? </Typography>
? ? ? ? <Typography
? ? ? ? ? variant="body2"
? ? ? ? ? sx={{ flex: 1, order: 3, bgcolor: 'info.main', color: 'white', p: 2 }}
? ? ? ? >
? ? ? ? ? Additional content (Order: 3)
? ? ? ? </Typography>
? ? ? </Container>
? ? ? <footer
? ? ? ? style={{
? ? ? ? ? display: 'flex',
? ? ? ? ? justifyContent: 'center',
? ? ? ? ? alignItems: 'center',
? ? ? ? ? height: '10vh',
? ? ? ? ? backgroundColor: '#f0f0f0',
? ? ? ? }}
? ? ? >
? ? ? ? <Typography variant="body2">? {new Date().getFullYear()} My App</Typography>
? ? ? </footer>
? ? </div>
? );
};
export default App;
Explanation:
In this updated example, we have added more cases to demonstrate different Flex Item options:
Multiple Flex Items:
We have added an additional Typography element with variant="body2" to create another Flex Item inside the Container.
flex and order Properties:
Each Typography element now has its own flex and order properties to showcase different layouts.
bgcolor and color Properties (sx prop):
We use the sx prop to apply custom styling to each Flex Item. We set different background colors (bgcolor) and text colors (color) for each item to differentiate them visually.
The result is a Flexbox layout where the Flex Items ("Welcome to My App!", "This is the main content of the page.", and "Additional content") are laid out in a column, occupying different amounts of vertical space, and appearing in a specific order within the container. The header and footer remain unchanged.
By default, all elements have order 0. If we want to move an element to the beginning, we have to give it a value of less than zero. Let's try the previous example, but instead of a column container, we will try vertical and remove the order property.
<Container
sx={{
display: "flex",
flexDirection: "row", // Main axis runs
justifyContent: "center",
alignItems: "center",
height: "40vh"
}}
>
<Typography
variant="h4"
sx={{ flex: 1, bgcolor: "primary.main", color: "white", p: 2 }}
>
Welcome to My App! (Order: 0)
</Typography>
<Typography
variant="body1"
sx={{ flex: 2,
bgcolor: "secondary.main",
color: "white",
p: 2 }}
>
This is the main content of the page. (Order: 0)
</Typography>
<Typography
variant="body2"
sx={{
flex: 1,
bgcolor: "info.main",
color: "white",
p: 2
}}
>
Additional content (Order: 0)
</Typography>
</Container>
It should look as follows:
Now to move the Middle item to the left, we will need to give it a number less than zero. I will give it -1
<Typography
variant="body1"
sx={{ flex: 2,
order: -1,
bgcolor: "secondary.main",
color: "white",
p: 2 }}
>
This is the main content of the page. (Order: -1)
</Typography>
Now, let's align the flex items using alignSelf
alignSelf:"flex-start",
As you noticed, here, The?alignItems?property in the container and alignSelf in the items are used to align flex items along the cross-axis of the flex container. The cross axis is the perpendicular axis to the main axis. So, if the?flexDirection?is set to 'row', the cross-axis runs vertically, and if it's set to 'column', the cross-axis runs horizontally.
Let's see this by examples:
In the previous example, align both content and items to center in the container, as follows:
<Container
sx={{
display: "flex",
flexDirection: "row", // Main axis runs
justifyContent: "center",
alignItems: "center",
height: "40vh"
}}>
Now change alignItems to flex-start
alignItems: "flex-start",
They align to the top of the page, as you can see. Now, you can change it per item to get each item a separate configuration.
Let's change the container back to the center again.
alignItems: "center",
Now change the second item alignSelf to flex-start
<Typography
variant="body1"
sx={{
flex: 2,
bgcolor: "secondary.main",
color: "white",
alignSelf: "flex-start",
p: 2
}}>
These are all the available values for alignSelf
? alignItems: 'stretch',
'flex-start',
'flex-end',
'center',
'baseline',
'stretch'
Here is the flex-end
Now, change the first to start and the last to stretch and watch the result.
=======
Flexbox Cheatsheet
Below is a cheatsheet for Flex Container and Flex Item properties using Material-UI v5 (styled with the `sx` prop).
Flex Container (Parent) Properties:
<Container sx={{
? display: 'flex',
? flexDirection: 'row', // 'row', 'row-reverse', 'column', 'column-reverse'
? flexWrap: 'nowrap', // 'nowrap', 'wrap', 'wrap-reverse'
? justifyContent: 'flex-start', // 'flex-start', 'flex-end', 'center', 'space-between', 'space-around', 'space-evenly'
? alignItems: 'stretch', // 'flex-start', 'flex-end', 'center', 'baseline', 'stretch'
? alignContent: 'stretch', // 'flex-start', 'flex-end', 'center', 'space-between', 'space-around', 'space-evenly', 'stretch'
}}>
? {/* Children (Flex Items) */}
</Container>
Flex Item (Child) Properties:
<Typography sx={{
? flexGrow: 1, // 0 (none), positive integer
? flexShrink: 1, // 0 (none), positive integer
? flexBasis: 'auto', // 'auto', any length value, percentage
? flex: '1 1 auto', // shorthand for flex-grow, flex-shrink, flex-basis
? alignSelf: 'auto', // 'auto', 'flex-start', 'flex-end', 'center', 'baseline', 'stretch'
? order: 0, // integer
}}>
? {/* Content */}
</Typography>
Explanation:
1. Flex Container Properties:
??- `display: 'flex'`: Specifies the element as a flex container.
??- `flexDirection`: Sets the main axis direction (horizontal or vertical).
??- `flexWrap`: Determines whether flex items should wrap to a new line.
??- `justifyContent`: Aligns flex items along the main axis.
??- `alignItems`: Aligns flex items along the cross axis.
??- `alignContent`: Aligns multiple lines of flex items when wrapping occurs.
2. Flex Item Properties:
??- `flexGrow`: Specifies how much a flex item can grow relative to other items.
??- `flexShrink`: Defines how much a flex item can shrink relative to other items.
??- `flexBasis`: Specifies the initial size of a flex item before remaining space is distributed.
??- `flex`: Shorthand for `flexGrow`, `flexShrink`, and `flexBasis`.
??- `alignSelf`: Aligns a specific flex item along the cross axis, overriding the container's `alignItems`.
??- `order`: Sets the order of a flex item.
Second: Creating a Grid-based layout
Next, we will create a layout using Material-UI Grid, which offers more control and flexibility for responsive designs.
import React from 'react';
import { AppBar, Toolbar, Typography, Grid, Paper } from '@mui/material';
const App = () => {
? return (
? ? <div>
? ? ? <AppBar position="static">
? ? ? ? <Toolbar>
? ? ? ? ? <Typography variant="h6">My App</Typography>
? ? ? ? </Toolbar>
? ? ? </AppBar>
? ? ? <Grid container spacing={3}>
? ? ? ? <Grid item xs={12}>
? ? ? ? ? <Paper
? ? ? ? ? ? sx={{
? ? ? ? ? ? ? padding: 2,
? ? ? ? ? ? ? textAlign: 'center',
? ? ? ? ? ? ? color: 'text.primary',
? ? ? ? ? ? ? backgroundColor: 'primary.main',
? ? ? ? ? ? }}
? ? ? ? ? >
? ? ? ? ? ? <Typography variant="h4">Welcome to My App!</Typography>
? ? ? ? ? ? <Typography variant="body1">
? ? ? ? ? ? ? This is the main content of the page.
? ? ? ? ? ? </Typography>
? ? ? ? ? </Paper>
? ? ? ? </Grid>
? ? ? </Grid>
? ? ? <footer
? ? ? ? style={{
? ? ? ? ? display: 'flex',
? ? ? ? ? justifyContent: 'center',
? ? ? ? ? alignItems: 'center',
? ? ? ? ? height: '10vh',
? ? ? ? ? backgroundColor: '#f0f0f0',
? ? ? ? }}
? ? ? >
? ? ? ? <Typography variant="body2">? {new Date().getFullYear()} My App</Typography>
? ? ? </footer>
? ? </div>
? );
};
export default App;
Grid-based Layout:
In the second part of the code, we create a Grid-based layout. Material-UI's Grid component provides a two-dimensional layout model, allowing us to arrange items in both rows and columns.
Footer Styling:
For both layouts, we create a simple footer with copyright text at the bottom of the page. In both cases, we use Flexbox to center the text both vertically and horizontally within the footer.
Best Practices:
Responsive Design:
Flexbox and Grid are powerful tools for creating responsive layouts. Always strive to make your layouts responsive to different screen sizes by using media queries or Material-UI's responsive grid system.
Use Material-UI Components:
Material-UI provides a wide range of pre-designed components that follow Material Design guidelines. Utilizing these components not only saves development time but also ensures a consistent and visually appealing user interface.
Separation of Concerns:
As demonstrated in the code, avoid using inline styles and prefer using Material-UI's styling solution (sx prop) or separate CSS files. This keeps your codebase organized and makes it easier to manage styles across components.
Component Modularity:
Break down your layout into smaller, reusable components. This promotes a modular design, making it easier to maintain and test your application.
Flexbox for One-Dimensional Layouts:
Use Flexbox when you need to arrange elements in a single row or column. It excels at handling one-dimensional layouts. It is usually used with Component Layout.
Grid is more suitable for complex layouts involving multiple rows and columns. It offers a more flexible and powerful two-dimensional layout model. The Grid is used for the full page Layout.
Optimize for Performance:
Keep an eye on performance, especially when using complex layouts. Avoid excessive nesting of grids or excessive use of Flexbox properties that could impact rendering performance.
Conclusion:
Building web page layouts using Flexbox and Grid in React and Material-UI can greatly simplify the development process and create responsive, visually pleasing interfaces. By utilizing Material-UI's components and adhering to best practices, you can build maintainable, scalable, and efficient web page layouts for various devices and screen sizes. Remember to experiment and fine-tune your layouts to fit the specific requirements of your project. Happy coding!
Great insights!