Cart and Checkout

🚧

This guide is outdated and will be updated shortly.

The Cart

It’s common to have a cart open as a drawer, sliding from right to left to indicate a product was added to the cart. This allows the customer to edit the quantity without navigating away from their current page.

This section will cover the cart drawer and normal cart page. The cart page isn't a necessity, but it can serve as a landing page for the customer if they navigate back from the Shopify checkout page.

For both scenarios, we need specific data points:
-a list of products in the cart
-the total price of the products
-a link to redirect us to checkout itself.

Luckily, the frontend-checkout package provides all of this information via the useCartState hook.

This guide will cover creating:
-CartItem: responsible for rendering a single row of a product in the cart.
-CartItems: shows a list of CartItems.
-CartDrawer: a section that will act as a wrapper and will handle the drawer itself.

Creating CartItem

The CartItem component accepts a product as a prop coming from frontend-checkout's useCartState hook, which we will cover in the next step.

// CartItem component
import * as React from 'react'
import { useCartActions } from 'frontend-checkout'
import { IconButton } from '@chakra-ui/react'
import Container from 'Components/Container'
import Flex from 'Components/Flex'
import Heading from 'Components/Heading'
import Icon from 'Components/Icon'
import Link from 'Components/Link'
import NumberInput from 'Components/NumberInput'
import Text from 'Components/Text'

const CartItem = ({ product }) => {
  const { id, quantity, title: name, variant } = product
  const { image, price, product: variantProduct, title: variantTitle } = variant
  const { src } = image
  const { handle: slug } = variantProduct
  const { removeItems, updateItems } = useCartActions()

  const onChangeItemQuantity = (_, quantityAsNumber) => {
    updateItems({ id, quantity: quantityAsNumber })
  }

  return (
    <Flex
      align="center"
      flexDirection={{ base: 'column', lg: 'row' }}
      justify="center"
      position="relative"
      py={{ base: 1, lg: 2 }}
    >
      <Container maxW={{ base: 'xs', lg: 'full' }} minW={{ lg: 'lg' }} p="1">
        <Link to={`/products/${slug}`}>
          <Flex align={{ lg: 'center' }} alignSelf={{ base: 'flex-start', lg: 'center' }}>
            <Container flex={{ base: '0 0 80px', lg: '0 0 120px' }}>
              <img alt="" src={src} height="120px" width="180px" sizes="120px" />
            </Container>
            <Container pl="4">
              <Heading as="h3" color="black" fontWeight="semibold" size="sm">
                {name}
              </Heading>
              {variantTitle && (
                <Text fontSize="sm" noOfLines={1}>
                  {variantTitle}
                </Text>
              )}
            </Container>
          </Flex>
        </Link>
      </Container>
      <Flex alignSelf={{ base: 'flex-end', lg: 'center' }} px={{ base: 2, lg: 0 }}>
        <Container
          textAlign="center"
          display={{ base: 'none', lg: 'block' }}
          fontWeight="semibold"
          p="1"
          w="36"
        >
          ${price}
        </Container>
        <Container textAlign="center" p="1" w="36">
          <NumberInput
            defaultValue={quantity}
            onChange={onChangeItemQuantity}
            inputProps={{
              'aria-label': 'Product quantity',
              size: 'xs',
            }}
            buttonProps={{
              size: 'xs',
            }}
          />
        </Container>
        <Container textAlign={{ base: 'right', lg: 'center' }} fontWeight="semibold" p="1" w="36">
          ${Number(price) * quantity}
        </Container>
      </Flex>
      <Container
        textAlign="right"
        position={{ base: 'absolute', lg: 'relative' }}
        p={{ lg: 1 }}
        top="0"
        right="0"
        w={{ lg: 20 }}
      >
        <IconButton
          icon={<Icon icon="CloseIcon" />}
          aria-label={`Remove ${name} from cart`}
          border="0"
          borderRadius="0"
          size="xs"
          variant="outline"
          _hover={{ color: 'gray.700' }}
          onClick={() => removeItems(id)}
        />
      </Container>
    </Flex>
  )
}

export default CartItem

Creating CartItems

The useCartState hook will give us access to all products a customer may have in their cart, the subtotalprice, and the checkoutUrl.

// CartItems component
import * as React from 'react'
import { useCartState } from 'frontend-checkout'
import CartItem from 'Components/CartItem'
import Container from 'Components/Container'
import Divider from 'Components/Divider'
import Flex from 'Components/Flex'
import Link from 'Components/Link'
import Text from 'Components/Text'

const CartItems = () => {
  const { checkoutUrl, items, subtotalPrice } = useCartState()

  return (
    <Container w={{ base: '95%', lg: '5xl' }} mx="auto">
      <Text fontSize="lg" fontWeight="semibold" my="4">
        Shopping cart ({items.length})
      </Text>
      {items.length ? (
        <React.Fragment>
          {items.map(product => (
            <Container key={product.id}>
              <CartItem product={product} />
              <Divider my="4" borderBottomWidth="1px" />
            </Container>
          ))}
          <Container maxW={{ base: 'full', lg: 'md' }} m="0 auto" mr={{ lg: '0' }}>
            <Flex justifyContent="space-between" my="4">
              <Text fontWeight="semibold">Subtotal:</Text>
              <Text>${subtotalPrice}</Text>
            </Flex>
            <Flex flexDirection={{ base: 'column', lg: 'row' }} justifyContent="space-between">
              <Link to="/" as="button" variant="primary">
                Continue shopping
              </Link>
              <Link to={checkoutUrl} as="button" variant="secondary" target="_self">
                Checkout
              </Link>
            </Flex>
          </Container>
        </React.Fragment>
      ) : (
        <React.Fragment>
          <Text>Your cart is currently empty.</Text>
          <Link to="/" as="button" variant="secondary">
            Start shopping
          </Link>
        </React.Fragment>
      )}
    </Container>
  )
}

export default CartItems

Creating CartDrawer

This step will assemble everything in the CartDrawer section. We will use hideCart from useCartActions and isCartShown from the useCartState hook and have the showCart function to display the CartDrawer when a product is successfully added to the cart.

// CartDrawer section
import * as React from 'react'
import { useCartActions, useCartState } from 'frontend-checkout'
import CartItems from 'Components/CartItems'
import Drawer from 'Components/Drawer'

const CartDrawer = () => {
  const { hideCart } = useCartActions()
  const { isCartShown } = useCartState()

  return (
    <Drawer isOpen={isCartShown} onClose={hideCart} size="md">
      <CartItems />
    </Drawer>
  )
}

export default CartDrawer

The CartDrawer section will live inside the App component. If you are using the Starter Kit, an App component already exists and you will just need to import the CartDrawer into it:

import React from 'react'
import { ChakraProvider } from '@chakra-ui/react'
import { theme } from 'Components/Theme'
import CartDrawer from 'Components/CartDrawer'

const App = props => {
  const { children } = props

  return (
    <ChakraProvider theme={theme}>
      <CartDrawer />
      {children}
    </ChakraProvider>
  )
}

export default App

You will now be able to see the CartDrawer if you add a product to the cart.

The Cart Page

Similar to the CartDrawer, the Cart page will also show a list of the products and will use CartItems.

As a wrapper to the CartItems, we will create a section called CartPage and call the CartItems:

import * as React from 'react'
import CartItems from 'Components/CartItems'
import Container from 'Components/Container'

const CartPage = () => (
  <Container>
    <CartItems />
  </Container>
)

export default CartPage

Next, create a page called Cart, making sure to use /cart for the path, and add the CartPage section to the Cart page. Reference Adding a section in the Homepage Guide if an example is needed.

The cart page is now complete and your customers can now add products to their cart and checkout!


What’s Next
Did this page help you?