How to Build an Add to Cart Page with React and MUI 5

In this tutorial, we’ll create shopping add to cart page in React Material-UI (MUI) version 5. We’ll create a simple product card with an Add to Cart button and a cart page that lists all added items. Please note that you’ll need to have a React project set up with MUI 5 installed.

Install & Setup Vite + React + Typescript + MUI 5

React MUI 5 Simple Add to Cart Page

First, let’s create a ProductCard component that displays a product and an Add to Cart button.

// ProductCard.jsx
import React from 'react';
import { Card, CardMedia, CardContent, CardActions, Typography, Button } from '@mui/material';

const ProductCard = ({ product, onAddToCart }) => {
  return (
    <Card sx={{ maxWidth: 345 }}>
      <CardMedia
        component="img"
        height="140"
        image={product.image}
        alt={product.name}
      />
      <CardContent>
        <Typography gutterBottom variant="h5" component="div">
          {product.name}
        </Typography>
        <Typography variant="body2" color="text.secondary">
          {product.description}
        </Typography>
      </CardContent>
      <CardActions>
        <Button size="small" onClick={() => onAddToCart(product)}>
          Add to Cart
        </Button>
      </CardActions>
    </Card>
  );
};

export default ProductCard;

Then, let’s create a CartPage component that lists all the items that have been added to the cart.

// CartPage.jsx
import React from 'react';
import { List, ListItem, ListItemText, ListItemAvatar, Avatar, Typography } from '@mui/material';

const CartPage = ({ cartItems }) => {
  return (
    <List>
      {cartItems.length === 0 ? (
        <Typography variant="h6">Your cart is empty</Typography>
      ) : (
        cartItems.map((item) => (
          <ListItem key={item.id}>
            <ListItemAvatar>
              <Avatar alt={item.name} src={item.image} />
            </ListItemAvatar>
            <ListItemText primary={item.name} secondary={`Quantity: ${item.quantity}`} />
          </ListItem>
        ))
      )}
    </List>
  );
};

export default CartPage;

Now, you’ll need to manage the state in your main component or page. Here’s a simple App component that brings everything together.

// App.js
import React, { useState } from 'react';
import ProductCard from './ProductCard';
import CartPage from './CartPage';
import { Container, Grid } from '@mui/material';

const products = [
  // Replace with your actual product data
  { id: 1, name: 'Product 1', description: 'This is product 1', image: 'path/to/image1.jpg' },
  { id: 2, name: 'Product 2', description: 'This is product 2', image: 'path/to/image2.jpg' },
  // ... more products
];

const App = () => {
  const [cart, setCart] = useState([]);

  const handleAddToCart = (product) => {
    setCart((prevCart) => {
      const isProductInCart = prevCart.find((item) => item.id === product.id);
      if (isProductInCart) {
        return prevCart.map((item) =>
          item.id === product.id ? { ...item, quantity: item.quantity + 1 } : item
        );
      }
      return [...prevCart, { ...product, quantity: 1 }];
    });
  };

  return (
    <Container>
      <Grid container spacing={4}>
        {products.map((product) => (
          <Grid item key={product.id} xs={12} sm={6} md={4}>
            <ProductCard product={product} onAddToCart={handleAddToCart} />
          </Grid>
        ))}
      </Grid>
      <CartPage cartItems={cart} />
    </Container>
  );
};

export default App;
 mui 5 shopping cart

React MUI 5 Product Listing Page with Shopping Cart Overview

We will Create a fully functional shopping cart using React and MUI 5, providing features like tracking the total price and quantity of items. you can split React components to improve code clarity and organization.

import { useState } from "react";
import {
  Card,
  CardMedia,
  CardContent,
  CardActions,
  Typography,
  Button,
  Grid,
  Box,
  List,
  ListItem,
  ListItemText,
  Divider,
  Paper,
} from "@mui/material";

const initialProducts = [
  {
    id: 1,
    name: "Laptop",
    price: 999,
    description: "High-performance laptop",
    image: "https://via.placeholder.com/100x100",
  },
  {
    id: 2,
    name: "Smartphone",
    price: 699,
    description: "Latest model smartphone",
    image: "https://via.placeholder.com/100x100",
  },
  // Add more products as needed
];

const ProductCard = ({ product, onAdd }) => (
  <Card raised>
    <CardMedia
      component="img"
      height="140"
      image={product.image}
      alt={product.name}
    />
    <CardContent>
      <Typography gutterBottom variant="h6" component="div">
        {product.name}
      </Typography>
      <Typography variant="body2" color="text.secondary">
        {product.description}
      </Typography>
      <Typography variant="body1">${product.price.toFixed(2)}</Typography>
    </CardContent>
    <CardActions>
      <Button size="small" variant="contained" onClick={() => onAdd(product)}>
        Add to Cart
      </Button>
    </CardActions>
  </Card>
);

const ShoppingCartOverview = ({ cartItems }) => (
  <Paper elevation={3} sx={{ p: 2 }}>
    <Typography variant="h6" gutterBottom>
      Shopping Cart
    </Typography>
    <Divider />
    <List>
      {cartItems.map((item, index) => (
        <ListItem key={index} divider>
          <ListItemText
            primary={item.name}
            secondary={`Quantity: ${item.quantity}`}
          />
          <Typography variant="body2">
            ${(item.price * item.quantity).toFixed(2)}
          </Typography>
        </ListItem>
      ))}
    </List>
    <Typography variant="h6">
      Total: $
      {cartItems
        .reduce((total, item) => total + item.price * item.quantity, 0)
        .toFixed(2)}
    </Typography>
  </Paper>
);

const ProductListingPage = () => {
  const [products] = useState(initialProducts);
  const [cart, setCart] = useState([]);

  const handleAddToCart = (productToAdd) => {
    setCart((prevCart) => {
      const productExists = prevCart.find(
        (item) => item.id === productToAdd.id
      );
      if (productExists) {
        return prevCart.map((item) =>
          item.id === productToAdd.id
            ? { ...item, quantity: item.quantity + 1 }
            : item
        );
      }
      return [...prevCart, { ...productToAdd, quantity: 1 }];
    });
  };

  return (
    <Box sx={{ flexGrow: 1, p: 2 }}>
      <Grid container spacing={2}>
        <Grid item xs={12} md={8}>
          <Grid container spacing={2}>
            {products.map((product) => (
              <Grid item key={product.id} xs={12} sm={6} md={4}>
                <ProductCard product={product} onAdd={handleAddToCart} />
              </Grid>
            ))}
          </Grid>
        </Grid>
        <Grid item xs={12} md={4}>
          <ShoppingCartOverview cartItems={cart} />
        </Grid>
      </Grid>
    </Box>
  );
};

export default ProductListingPage;
 mui shopping cart items
Aaronn
Aaronn

Hey there! I'm Aaronn, a Full Stack Developer who's all about React, NEXTJS, Node.js, and Tailwind CSS. I'm on a mission to craft awesome websites that look great and work even better.