In this tutorial, we will create checkout page in react with material ui (mui 5). We will see checkout page, checkout process steps example with react material UI 5.
Install & Setup Vite + React + Typescript + MUI 5
React Material UI 5 Checkout Page Example
1. Create react mui 5 simple checkout page using react-mui Box, Container, TextField, Button, Typography, Card, CardContent, Grid component.
import {
Box,
Container,
TextField,
Button,
Typography,
Card,
CardContent,
Grid,
} from "@mui/material";
export default function Checkout() {
return (
<Container maxWidth="sm">
<Box sx={{ mt: 4 }}>
<Typography variant="h4" align="center">
Checkout
</Typography>
</Box>
<Card variant="outlined" sx={{ mt: 2 }}>
<CardContent>
<Box component="form">
<TextField
label="Name"
variant="outlined"
fullWidth
margin="normal"
/>
<TextField
label="Address"
variant="outlined"
fullWidth
margin="normal"
/>
<TextField
label="Credit Card Number"
variant="outlined"
fullWidth
margin="normal"
type="number"
inputProps={{ maxLength: 16 }}
/>
<TextField
label="CVV"
variant="outlined"
fullWidth
margin="normal"
type="number"
inputProps={{ maxLength: 3 }}
/>
<Grid container spacing={2}>
<Grid item xs={6}>
<TextField
label="Expiry Month"
variant="outlined"
fullWidth
margin="normal"
type="number"
inputProps={{ min: 1, max: 12 }}
/>
</Grid>
<Grid item xs={6}>
<TextField
label="Expiry Year"
variant="outlined"
fullWidth
margin="normal"
type="number"
inputProps={{ min: 2023 }}
/>
</Grid>
</Grid>
<Button
variant="contained"
color="primary"
type="submit"
fullWidth
sx={{ mt: 2 }}
>
Pay Now
</Button>
</Box>
</CardContent>
</Card>
</Container>
);
}
2. react mui 5 checkout page with process steps.
create AddressForm.js or AddressForm.jsx
AddressForm.js
import * as React from 'react';
import Grid from '@mui/material/Grid';
import Typography from '@mui/material/Typography';
import TextField from '@mui/material/TextField';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
export default function AddressForm() {
return (
<>
<Typography variant="h6" gutterBottom>
Shipping address
</Typography>
<Grid container spacing={3}>
<Grid item xs={12} sm={6}>
<TextField
required
id="firstName"
name="firstName"
label="First name"
fullWidth
autoComplete="given-name"
variant="standard"
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
required
id="lastName"
name="lastName"
label="Last name"
fullWidth
autoComplete="family-name"
variant="standard"
/>
</Grid>
<Grid item xs={12}>
<TextField
required
id="address1"
name="address1"
label="Address line 1"
fullWidth
autoComplete="shipping address-line1"
variant="standard"
/>
</Grid>
<Grid item xs={12}>
<TextField
id="address2"
name="address2"
label="Address line 2"
fullWidth
autoComplete="shipping address-line2"
variant="standard"
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
required
id="city"
name="city"
label="City"
fullWidth
autoComplete="shipping address-level2"
variant="standard"
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
id="state"
name="state"
label="State/Province/Region"
fullWidth
variant="standard"
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
required
id="zip"
name="zip"
label="Zip / Postal code"
fullWidth
autoComplete="shipping postal-code"
variant="standard"
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
required
id="country"
name="country"
label="Country"
fullWidth
autoComplete="shipping country"
variant="standard"
/>
</Grid>
<Grid item xs={12}>
<FormControlLabel
control={<Checkbox color="secondary" name="saveAddress" value="yes" />}
label="Use this address for payment details"
/>
</Grid>
</Grid>
</>
);
}
create PaymentForm.js or PaymentForm.jsx
PaymentForm.js
import * as React from 'react';
import Typography from '@mui/material/Typography';
import Grid from '@mui/material/Grid';
import TextField from '@mui/material/TextField';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
export default function PaymentForm() {
return (
<>
<Typography variant="h6" gutterBottom>
Payment method
</Typography>
<Grid container spacing={3}>
<Grid item xs={12} md={6}>
<TextField
required
id="cardName"
label="Name on card"
fullWidth
autoComplete="cc-name"
variant="standard"
/>
</Grid>
<Grid item xs={12} md={6}>
<TextField
required
id="cardNumber"
label="Card number"
fullWidth
autoComplete="cc-number"
variant="standard"
/>
</Grid>
<Grid item xs={12} md={6}>
<TextField
required
id="expDate"
label="Expiry date"
fullWidth
autoComplete="cc-exp"
variant="standard"
/>
</Grid>
<Grid item xs={12} md={6}>
<TextField
required
id="cvv"
label="CVV"
helperText="Last three digits on signature strip"
fullWidth
autoComplete="cc-csc"
variant="standard"
/>
</Grid>
<Grid item xs={12}>
<FormControlLabel
control={<Checkbox color="secondary" name="saveCard" value="yes" />}
label="Remember credit card details for next time"
/>
</Grid>
</Grid>
</>
);
}
create Review.js or Review.jsx
Review.js
import * as React from 'react';
import Typography from '@mui/material/Typography';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemText from '@mui/material/ListItemText';
import Grid from '@mui/material/Grid';
const products = [
{
name: 'Product 1',
desc: 'A nice thing',
price: '$9.99',
},
{
name: 'Product 2',
desc: 'Another thing',
price: '$3.45',
},
{
name: 'Product 3',
desc: 'Something else',
price: '$6.51',
},
{
name: 'Product 4',
desc: 'Best thing of all',
price: '$14.11',
},
{ name: 'Shipping', desc: '', price: 'Free' },
];
const addresses = ['1 MUI Drive', 'Reactville', 'Anytown', '99999', 'USA'];
const payments = [
{ name: 'Card type', detail: 'Visa' },
{ name: 'Card holder', detail: 'Mr John Smith' },
{ name: 'Card number', detail: 'xxxx-xxxx-xxxx-1234' },
{ name: 'Expiry date', detail: '04/2024' },
];
export default function Review() {
return (
<>
<Typography variant="h6" gutterBottom>
Order summary
</Typography>
<List disablePadding>
{products.map((product) => (
<ListItem key={product.name} sx={{ py: 1, px: 0 }}>
<ListItemText primary={product.name} secondary={product.desc} />
<Typography variant="body2">{product.price}</Typography>
</ListItem>
))}
<ListItem sx={{ py: 1, px: 0 }}>
<ListItemText primary="Total" />
<Typography variant="subtitle1" sx={{ fontWeight: 700 }}>
$34.06
</Typography>
</ListItem>
</List>
<Grid container spacing={2}>
<Grid item xs={12} sm={6}>
<Typography variant="h6" gutterBottom sx={{ mt: 2 }}>
Shipping
</Typography>
<Typography gutterBottom>John Smith</Typography>
<Typography gutterBottom>{addresses.join(', ')}</Typography>
</Grid>
<Grid item container direction="column" xs={12} sm={6}>
<Typography variant="h6" gutterBottom sx={{ mt: 2 }}>
Payment details
</Typography>
<Grid container>
{payments.map((payment) => (
<React.Fragment key={payment.name}>
<Grid item xs={6}>
<Typography gutterBottom>{payment.name}</Typography>
</Grid>
<Grid item xs={6}>
<Typography gutterBottom>{payment.detail}</Typography>
</Grid>
</React.Fragment>
))}
</Grid>
</Grid>
</Grid>
</>
);
}
Now create Checkout.js or Checkout.jsx and import AddressForm.js, PaymentForm.js, Review.js.
Checkout.js
import * as React from 'react';
import CssBaseline from '@mui/material/CssBaseline';
import AppBar from '@mui/material/AppBar';
import Box from '@mui/material/Box';
import Container from '@mui/material/Container';
import Toolbar from '@mui/material/Toolbar';
import Paper from '@mui/material/Paper';
import Stepper from '@mui/material/Stepper';
import Step from '@mui/material/Step';
import StepLabel from '@mui/material/StepLabel';
import Button from '@mui/material/Button';
import Link from '@mui/material/Link';
import Typography from '@mui/material/Typography';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import AddressForm from './AddressForm';
import PaymentForm from './PaymentForm';
import Review from './Review';
function Copyright() {
return (
<Typography variant="body2" color="text.secondary" align="center">
{'Copyright © '}
<Link color="inherit" href="https://mui.com/">
Your Website
</Link>{' '}
{new Date().getFullYear()}
{'.'}
</Typography>
);
}
const steps = ['Shipping address', 'Payment details', 'Review your order'];
function getStepContent(step) {
switch (step) {
case 0:
return <AddressForm />;
case 1:
return <PaymentForm />;
case 2:
return <Review />;
default:
throw new Error('Unknown step');
}
}
const theme = createTheme();
export default function Checkout() {
const [activeStep, setActiveStep] = React.useState(0);
const handleNext = () => {
setActiveStep(activeStep + 1);
};
const handleBack = () => {
setActiveStep(activeStep - 1);
};
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<AppBar
position="absolute"
color="default"
elevation={0}
sx={{
position: 'relative',
borderBottom: (t) => `1px solid ${t.palette.divider}`,
}}
>
<Toolbar>
<Typography variant="h6" color="inherit" noWrap>
Company name
</Typography>
</Toolbar>
</AppBar>
<Container component="main" maxWidth="sm" sx={{ mb: 4 }}>
<Paper variant="outlined" sx={{ my: { xs: 3, md: 6 }, p: { xs: 2, md: 3 } }}>
<Typography component="h1" variant="h4" align="center">
Checkout
</Typography>
<Stepper activeStep={activeStep} sx={{ pt: 3, pb: 5 }}>
{steps.map((label) => (
<Step key={label}>
<StepLabel>{label}</StepLabel>
</Step>
))}
</Stepper>
{activeStep === steps.length ? (
<React.Fragment>
<Typography variant="h5" gutterBottom>
Thank you for your order.
</Typography>
<Typography variant="subtitle1">
Your order number is #2001539. We have emailed your order
confirmation, and will send you an update when your order has
shipped.
</Typography>
</React.Fragment>
) : (
<React.Fragment>
{getStepContent(activeStep)}
<Box sx={{ display: 'flex', justifyContent: 'flex-end' }}>
{activeStep !== 0 && (
<Button onClick={handleBack} sx={{ mt: 3, ml: 1 }}>
Back
</Button>
)}
<Button
variant="contained"
onClick={handleNext}
sx={{ mt: 3, ml: 1 }}
>
{activeStep === steps.length - 1 ? 'Place order' : 'Next'}
</Button>
</Box>
</React.Fragment>
)}
</Paper>
<Copyright />
</Container>
</ThemeProvider>
);
}