Blogs / Frontend Machine Coding

Frontend Machine Coding: How to Build a Shopping Cart Sidebar in React

A complete beginner-friendly blog on how to build a Shopping Cart Sidebar in React for frontend machine coding rounds. It covers component thinking, state management, cart logic, UI structure, derived values, localStorage persistence, cart badge count, safer quantity controls, edge cases, and interview tips in very easy language.

Apr 10, 202614 min readSevyDevy Team
ReactMachine CodingShopping CartFrontend InterviewuseStatelocalStorageComponent DesignUI Engineering

Table of content

  1. 1. Why Shopping Cart Sidebar is a Popular Machine Coding Question
  2. 2. What We Are Going to Build
  3. 3. First Think Like an Engineer, Not Like a Coder
  4. 4. Data Shape for Cart Item
  5. 5. Sample Product Data
  6. 6. Main React State
  7. 7. Persist Cart in localStorage
  8. 8. How Add to Cart Logic Should Work
  9. 9. How Quantity Increase and Decrease Should Work
  10. 10. Disable Decrease Button When Quantity is 1
  11. 11. Remove Item Logic
  12. 12. Derived Values: Total Quantity and Total Price
  13. 13. Add Item Count Badge on Cart Icon
  14. 14. Component Structure in React
  15. 15. Complete React Example
  16. 16. Why useMemo is Optional but Nice Here
  17. 17. Important UI States You Should Mention in Interview
  18. 18. Common Mistakes Beginners Make
  19. 19. How to Explain This Solution During a Machine Coding Round
  20. 20. How a CTO Would Evaluate This Feature
  21. 21. How You Can Extend This Further
  22. 22. Final Takeaway

A Shopping Cart Sidebar looks simple, but in interviews it tests many important frontend skills together. The interviewer can quickly see whether you know how to manage state, update UI correctly, calculate totals, handle repeated items, persist data properly, and structure React components in a clean way.

This is why this question is common in frontend machine coding rounds. It is not only about making a sidebar open from the right side of the screen. It is also about building a small but real product flow.

  • Can you manage cart state properly?
  • Can you design reusable React components?
  • Can you update quantity and remove items correctly?
  • Can you derive subtotal and total without storing unnecessary state?
  • Can you persist important UI data like cart items?
  • Can you keep code readable under time pressure?

What We Are Going to Build

We will build a React shopping cart sidebar that opens from the right side. It will show cart items, quantity controls, item price, subtotal, and total items. We will also add buttons to increase quantity, disable decrease when quantity is 1, remove an item separately, show an item count badge on the cart button, and persist cart data in localStorage.

The goal is not to make the fanciest UI. The goal is to build something interview-ready with clean logic and easy explanation.

First Think Like an Engineer, Not Like a Coder

Before writing code, break the feature into parts. This is one of the biggest differences between a beginner and a strong frontend engineer.

  • We need product data.
  • We need cart state.
  • We need localStorage persistence.
  • We need a cart button with badge count.
  • We need a sidebar to show current cart items.
  • We need actions: add, increase, decrease, remove.
  • We need derived values like total quantity and total price.

If you explain this breakdown in an interview before coding, it creates a very strong impression because it shows product and architecture thinking.

Data Shape for Cart Item

A good machine coding solution starts with a good data shape. If your data structure is messy, the rest of the solution becomes messy too.

type Product = {
  id: number;
  title: string;
  price: number;
  image: string;
};

type CartItem = Product & {
  quantity: number;
};

Here, CartItem reuses Product fields and adds quantity. This is a clean and scalable way to design the state.

Sample Product Data

const PRODUCTS: Product[] = [
  {
    id: 1,
    title: "Wireless Headphones",
    price: 2499,
    image: "https://via.placeholder.com/80",
  },
  {
    id: 2,
    title: "Smart Watch",
    price: 3999,
    image: "https://via.placeholder.com/80",
  },
  {
    id: 3,
    title: "Bluetooth Speaker",
    price: 1799,
    image: "https://via.placeholder.com/80",
  },
];

In a real application this data may come from an API, but in a machine coding round hardcoded mock data is completely fine unless the interviewer asks otherwise.

Main React State

For this problem, we mainly need two pieces of state: one for opening and closing the sidebar, and one for storing cart items. Since we also want persistence, we can initialize cart state from localStorage.

const [isCartOpen, setIsCartOpen] = useState(false);
const [cartItems, setCartItems] = useState<CartItem[]>(() => {
  const savedCart = localStorage.getItem("cart-items");
  return savedCart ? JSON.parse(savedCart) : [];
});

Keep state minimal. A common beginner mistake is storing too many things that can actually be calculated from existing state.

Persist Cart in localStorage

Persisting cart in localStorage is a very practical improvement. If the user refreshes the page, the cart should not disappear. This makes the feature feel more like a real product and less like a demo.

The important idea is simple: whenever cartItems changes, write the updated array into localStorage.

useEffect(() => {
  localStorage.setItem("cart-items", JSON.stringify(cartItems));
}, [cartItems]);

In interviews, this is a strong point because it shows that you think beyond just rendering UI. You also think about user continuity and basic product behavior.

How Add to Cart Logic Should Work

When a user clicks Add to Cart, there are only two possibilities. Either the item is already in the cart, or it is not.

If it already exists, increase the quantity. If it does not exist, add it with quantity 1.

const handleAddToCart = (product: Product) => {
  setCartItems((prev) => {
    const existingItem = prev.find((item) => item.id === product.id);

    if (existingItem) {
      return prev.map((item) =>
        item.id === product.id
          ? { ...item, quantity: item.quantity + 1 }
          : item
      );
    }

    return [...prev, { ...product, quantity: 1 }];
  });
};

This logic is very important. Interviewers often watch this part carefully because it shows whether you can update array state immutably in React.

How Quantity Increase and Decrease Should Work

Once items are inside the cart, users should be able to increase quantity from the sidebar itself. For decrease, a better user experience is to disable the decrease button when quantity is 1 and let removal happen through a dedicated Remove button.

const increaseQuantity = (id: number) => {
  setCartItems((prev) =>
    prev.map((item) =>
      item.id === id
        ? { ...item, quantity: item.quantity + 1 }
        : item
    )
  );
};

const decreaseQuantity = (id: number) => {
  setCartItems((prev) =>
    prev.map((item) =>
      item.id === id && item.quantity > 1
        ? { ...item, quantity: item.quantity - 1 }
        : item
    )
  );
};

This approach makes the behavior clearer. Quantity control is only for adjusting count, and Remove is only for deleting the item from cart.

Disable Decrease Button When Quantity is 1

This small detail makes the UI more predictable. If quantity is already 1, the decrease button should be disabled. That tells the user they cannot reduce further from there, and if they want to delete the item, they should use Remove.

<button
  onClick={() => decreaseQuantity(item.id)}
  disabled={item.quantity === 1}
>
  -
</button>

This is a nice interview detail because it shows UX awareness, not just code writing.

Remove Item Logic

const removeItem = (id: number) => {
  setCartItems((prev) => prev.filter((item) => item.id !== id));
};

This is simple, but it is still an important action. Most machine coding questions are not about complex code. They are about writing simple code correctly and clearly.

Derived Values: Total Quantity and Total Price

This is one of the most important frontend lessons. Do not store total quantity and total price in separate state variables when they can be derived from cartItems.

Why? Because duplicated state can go out of sync and create bugs.

const totalItems = cartItems.reduce(
  (sum, item) => sum + item.quantity,
  0
);

const totalPrice = cartItems.reduce(
  (sum, item) => sum + item.price * item.quantity,
  0
);

A very good line to say in interview is: I am keeping state minimal and computing derived values from source state to avoid inconsistency.

Add Item Count Badge on Cart Icon

A cart badge is a small thing, but it adds real usability. The user can instantly see how many items are inside the cart without opening it.

Since totalItems is already derived from cartItems, we can reuse it directly in the cart button or icon badge.

<button onClick={() => setIsCartOpen(true)}>
  Cart ({totalItems})
</button>

In a real UI, you can style this as a small circle badge near the cart icon. In machine coding, even a simple Cart (3) is enough to communicate the idea clearly.

Component Structure in React

Even in a small machine coding round, component thinking matters. You do not want one giant file with everything mixed together.

  • App: manages products, cart state, persistence, and layout
  • ProductList: shows available products
  • ProductCard: shows one product and Add to Cart button
  • CartSidebar: shows cart drawer UI
  • CartItemRow: shows one item inside the cart

If interview time is short, you can keep all code in one file. But still explain the ideal component breakdown. That shows senior thinking even if you do not fully split it during the round.

Complete React Example

import React, { useEffect, useMemo, useState } from "react";

type Product = {
  id: number;
  title: string;
  price: number;
  image: string;
};

type CartItem = Product & {
  quantity: number;
};

const PRODUCTS: Product[] = [
  {
    id: 1,
    title: "Wireless Headphones",
    price: 2499,
    image: "https://via.placeholder.com/80",
  },
  {
    id: 2,
    title: "Smart Watch",
    price: 3999,
    image: "https://via.placeholder.com/80",
  },
  {
    id: 3,
    title: "Bluetooth Speaker",
    price: 1799,
    image: "https://via.placeholder.com/80",
  },
];

export default function ShoppingCartSidebarExample() {
  const [isCartOpen, setIsCartOpen] = useState(false);
  const [cartItems, setCartItems] = useState<CartItem[]>(() => {
    const savedCart = localStorage.getItem("cart-items");
    return savedCart ? JSON.parse(savedCart) : [];
  });

  useEffect(() => {
    localStorage.setItem("cart-items", JSON.stringify(cartItems));
  }, [cartItems]);

  const handleAddToCart = (product: Product) => {
    setCartItems((prev) => {
      const existingItem = prev.find((item) => item.id === product.id);

      if (existingItem) {
        return prev.map((item) =>
          item.id === product.id
            ? { ...item, quantity: item.quantity + 1 }
            : item
        );
      }

      return [...prev, { ...product, quantity: 1 }];
    });
    setIsCartOpen(true);
  };

  const increaseQuantity = (id: number) => {
    setCartItems((prev) =>
      prev.map((item) =>
        item.id === id
          ? { ...item, quantity: item.quantity + 1 }
          : item
      )
    );
  };

  const decreaseQuantity = (id: number) => {
    setCartItems((prev) =>
      prev.map((item) =>
        item.id === id && item.quantity > 1
          ? { ...item, quantity: item.quantity - 1 }
          : item
      )
    );
  };

  const removeItem = (id: number) => {
    setCartItems((prev) => prev.filter((item) => item.id !== id));
  };

  const totalItems = useMemo(
    () => cartItems.reduce((sum, item) => sum + item.quantity, 0),
    [cartItems]
  );

  const totalPrice = useMemo(
    () => cartItems.reduce((sum, item) => sum + item.price * item.quantity, 0),
    [cartItems]
  );

  return (
    <div style={{ padding: "24px", fontFamily: "Arial, sans-serif" }}>
      <div
        style={{
          display: "flex",
          justifyContent: "space-between",
          alignItems: "center",
          marginBottom: "24px",
        }}
      >
        <h1>Products</h1>
        <button onClick={() => setIsCartOpen(true)}>
          Cart ({totalItems})
        </button>
      </div>

      <div style={{ display: "grid", gap: "16px" }}>
        {PRODUCTS.map((product) => (
          <div
            key={product.id}
            style={{
              border: "1px solid #ddd",
              padding: "16px",
              borderRadius: "12px",
              display: "flex",
              alignItems: "center",
              gap: "16px",
            }}
          >
            <img src={product.image} alt={product.title} width={80} height={80} />
            <div style={{ flex: 1 }}>
              <h3>{product.title}</h3>
              <p>₹{product.price}</p>
            </div>
            <button onClick={() => handleAddToCart(product)}>Add to Cart</button>
          </div>
        ))}
      </div>

      {isCartOpen && (
        <div
          style={{
            position: "fixed",
            top: 0,
            right: 0,
            width: "360px",
            height: "100vh",
            background: "#fff",
            boxShadow: "-4px 0 10px rgba(0,0,0,0.1)",
            padding: "20px",
            overflowY: "auto",
          }}
        >
          <div
            style={{
              display: "flex",
              justifyContent: "space-between",
              alignItems: "center",
              marginBottom: "20px",
            }}
          >
            <h2>Your Cart</h2>
            <button onClick={() => setIsCartOpen(false)}>Close</button>
          </div>

          {cartItems.length === 0 ? (
            <p>Your cart is empty.</p>
          ) : (
            <>
              <div style={{ display: "grid", gap: "16px" }}>
                {cartItems.map((item) => (
                  <div
                    key={item.id}
                    style={{
                      borderBottom: "1px solid #eee",
                      paddingBottom: "12px",
                    }}
                  >
                    <div style={{ display: "flex", gap: "12px" }}>
                      <img src={item.image} alt={item.title} width={60} height={60} />
                      <div style={{ flex: 1 }}>
                        <h4 style={{ margin: 0 }}>{item.title}</h4>
                        <p style={{ margin: "6px 0" }}>
                          ₹{item.price} × {item.quantity}
                        </p>

                        <div style={{ display: "flex", gap: "8px", alignItems: "center" }}>
                          <button
                            onClick={() => decreaseQuantity(item.id)}
                            disabled={item.quantity === 1}
                          >
                            -
                          </button>
                          <span>{item.quantity}</span>
                          <button onClick={() => increaseQuantity(item.id)}>+</button>
                          <button onClick={() => removeItem(item.id)}>Remove</button>
                        </div>
                      </div>
                    </div>
                  </div>
                ))}
              </div>

              <div style={{ marginTop: "20px" }}>
                <h3>Total: ₹{totalPrice}</h3>
                <button style={{ width: "100%", padding: "12px" }}>
                  Checkout
                </button>
              </div>
            </>
          )}
        </div>
      )}
    </div>
  );
}

Why useMemo is Optional but Nice Here

In this example, totalItems and totalPrice are wrapped in useMemo. For a small app it is not mandatory, but it shows that you know these values depend only on cartItems and do not need recalculation on unrelated renders.

Still, do not force optimization everywhere. A strong frontend engineer knows when optimization is useful and when it only adds noise.

Important UI States You Should Mention in Interview

Good interview candidates do not stop at the happy path. They think about states.

  • Empty cart state
  • Sidebar open and close state
  • Cart persistence after refresh
  • Disabled decrease button at quantity 1
  • Separate remove action
  • Badge count update on every cart change
  • Long product title handling
  • Large number of cart items causing scrolling
  • Responsive layout for smaller screens

Even if you do not build every edge case in the round, mentioning them adds a lot of value.

Common Mistakes Beginners Make

  • Mutating state directly instead of returning new arrays or objects
  • Storing subtotal and total in separate state variables
  • Forgetting to merge quantity when item already exists in cart
  • Writing all logic inline inside JSX
  • Not handling empty cart state
  • Using array index as a key instead of stable item id
  • Reducing quantity to zero without a clear remove flow
  • Forgetting to persist or restore cart data from localStorage

These mistakes are very common, and interviewers notice them fast. Clean fundamentals matter more than clever tricks.

How to Explain This Solution During a Machine Coding Round

Your explanation matters almost as much as the code. A solid flow can be:

  • First, I will define product and cart item data structures.
  • Then I will keep minimal state: sidebar visibility and cart items.
  • Then I will initialize cart from localStorage and sync updates back into it.
  • Then I will build add, increase, decrease, and remove actions.
  • Then I will derive total quantity and total price from cart state.
  • Then I will show the cart badge count in the cart button.
  • Finally, I will render the sidebar and handle empty and filled states.

This makes you sound structured, calm, and product-minded. That is exactly what interviewers want.

How a CTO Would Evaluate This Feature

From a CTO or senior engineer perspective, this problem is small but revealing. It tells whether a frontend developer can think in terms of user flows, source of truth, composable UI, persistence, and state correctness.

A shopping cart is business-critical in ecommerce. If quantity logic is wrong, pricing is wrong. If state handling is weak, checkout trust is damaged. If refresh wipes the cart, users get frustrated. That is why even a small frontend task reflects real product engineering discipline.

How You Can Extend This Further

  • Add overlay behind sidebar
  • Animate sidebar opening and closing
  • Connect products to a real backend API
  • Use Context API or Zustand for global cart state
  • Sync cart with backend for logged-in users
  • Add coupon and discount support

These are good follow-up ideas if the interviewer asks how you would improve the solution for production.

Final Takeaway

A Shopping Cart Sidebar is a perfect frontend machine coding question because it tests much more than styling. It tests state design, immutable updates, derived data, persistence, user experience, and code structure.

If you learn how to build this properly in React, you are also learning how to think like a stronger frontend engineer. The secret is not writing more code. The secret is writing clear code with correct thinking.

Related blogs