If you’re new to web development or e-commerce, creating a custom Shopify storefront with React.js might sound daunting. But don’t worry! You've landed at the right place.
My beginner-friendly guide will walk you through every step, from setting up your Shopify store to building a beautiful, functional storefront using React.js.
By the end, you’ll have a working store displaying products and a basic cart, all explained in simple terms.
Why Build a Custom Shopify Storefront with React.js?
Shopify is a powerful platform for creating online stores, but its default themes might not always match your vision. A custom storefront lets you design a unique shopping experience tailored to your brand.
Using React.js, a popular JavaScript library, you can build fast, interactive, and reusable components for your store. Plus, Shopify’s Storefront API makes it easy to fetch product data and manage cart functionality.
This guide is perfect for beginners because:
- We’ll use simple tools and explain every step.
- You’ll learn practical React.js concepts like components and state management.
- You’ll see how to connect React.js with Shopify’s API.
Prerequisites
Before we start, make sure you have:
- A Shopify Account: Sign up for a free trial at shopify.com.
- Basic JavaScript Knowledge: Familiarity with variables, functions, and arrays is enough.
- Node.js Installed: Download it from nodejs.org. This lets you run JavaScript tools on your computer.
- A Text Editor: Use Visual Studio Code (free at code.visualstudio.com).
- A Shopify Storefront API Token: We’ll cover how to get this below. No prior React.js or Shopify experience? No problem! I’ll explain everything.
Step-by-Step Guide
Step 1: Set Up Your Shopify Store and Storefront API
To build a custom storefront, you need a Shopify store and access to its Storefront API, which lets your React app fetch products, prices, and more.
-
Create a Shopify Store:
- Go to shopify.com and sign up.
- Follow the prompts to set up a basic store. Add a few products (with names, prices, and images) for testing.
- Note your store’s domain, like
your-store.myshopify.com
.
-
Enable the Storefront API:
- Log in to your Shopify admin (e.g.,
your-store.myshopify.com/admin
). - Go to Apps > Develop apps > Create an app.
- Give your app a name, like “Custom Storefront.”
- Under API access, enable the Storefront API.
- Click Save, then copy the Storefront API access token. This is a secret key, so don’t share it publicly!
- The API endpoint for your store is
https://your-store.myshopify.com/api/2025-01/graphql.json
.
- Log in to your Shopify admin (e.g.,
-
Test the API (Optional):
query { products(first: 5) { edges { node { title } } } }
- Include your API token in the request headers (
X-Shopify-Storefront-Access-Token
). If you see product titles, your API is ready!
Step 2: Set Up Your React Project
React.js lets you build your storefront as reusable components, like product cards or a cart. We’ll use Vite, a fast tool for creating React projects.
-
Install Vite and Create a Project:
- Open your terminal (Command Prompt on Windows, Terminal on Mac/Linux).
- Run these commands:
npm create vite@latest shopify-storefront --template react cd shopify-storefront npm install
- This creates a folder called
shopify-storefront
with a basic React app.
-
Install Additional Tools:
- We’ll use Apollo Client to connect to Shopify’s GraphQL API and Tailwind CSS for easy styling.
- Run:
npm install @apollo/client graphql tailwindcss postcss autoprefixer npx tailwindcss init -p
- This installs Apollo Client (for API calls) and sets up Tailwind CSS.
-
Configure Tailwind CSS:
- Open
tailwind.config.js
in your project folder and replace its contents with:
/** @type {import('tailwindcss').Config} */ export default { content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], theme: { extend: {} }, plugins: [], };
- Open
-
Open
src/index.css
and add:
@tailwind base; @tailwind components; @tailwind utilities;
These settings make Tailwind CSS work with your React app.
-
Start the Development Server:
- Run:
npm run dev
- Open your browser to
http://localhost:5173
(or the URL shown in the terminal). You’ll see a default Vite + React page.
Step 3: Connect to Shopify’s Storefront API
Now, let’s connect your scalable React app to Shopify’s API using Apollo Client. This lets you fetch products and display them.
-
Set Up Apollo Client:
- Create a file to initialize Apollo Client, which handles API requests.
- Open
src/main.jsx
and replace its contents with:
import React from 'react'; import { createRoot } from 'react-dom/client'; import { ApolloClient, InMemoryCache, ApolloProvider, HttpLink } from '@apollo/client'; import App from './App'; const client = new ApolloClient({ link: new HttpLink({ uri: 'https://your-store.myshopify.com/api/2025-01/graphql.json', headers: { 'X-Shopify-Storefront-Access-Token': 'your-storefront-api-token', }, }), cache: new InMemoryCache(), }); const root = createRoot(document.getElementById('root')); root.render( <ApolloProvider client={client}> <App /> </ApolloProvider> );
- Replace
your-store.myshopify.com
with your store’s domain andyour-storefront-api-token
with your API token from Step 1. - This code:
- Creates an Apollo Client instance to talk to Shopify’s API.
- Wraps your app in
ApolloProvider
, so all components can use the API.
-
Test the Connection:
- For now, your app should still show the default page. We’ll update it to fetch products next.
Step 4: Build the Storefront Components
Let’s create components to display products and a cart. We’ll break this into:
- A main ` component to fetch and manage data.
- A
ProductList
component to show product cards. - A
Cart
component to show items added by the user.
-
Update the Main App Component:
- Replace
src/App.jsx
with:
- Replace
`
import React, { useState } from 'react';
import { useQuery, gql } from '@apollo/client';
import ProductList from './components/ProductList';
import Cart from './components/Cart';
const GET_PRODUCTS = gql
;
query {
products(first: 10) {
edges {
node {
id
title
handle
description
images(first: 1) {
edges {
node {
src
}
}
}
variants(first: 1) {
edges {
node {
id
priceV2 {
amount
currencyCode
}
}
}
}
}
}
}
}
function App() {
const { loading, error, data } = useQuery(GET_PRODUCTS);
const [cart, setCart] = useState([]);
const addToCart = (product) => {
const existing = cart.find((item) => item.id === product.id);
if (existing) {
setCart(cart.map(item => item.id === product.id ? { ...item, quantity: item.quantity + 1 } : item));
} else {
setCart([...cart, { ...product, quantity: 1 }]);
}
};
if (loading) return
Loading...
;if (error) return
Error: {error.message}
;const products = data.products.edges.map(({ node }) => ({
id: node.id,
title: node.title || 'Unnamed Product',
description: node.description || 'No description available',
image: node.images.edges[0]?.node.src || 'https://via.placeholder.com/150',
price: node.variants.edges[0]?.node.priceV2?.amount || '0.00',
currency: node.variants.edges[0]?.node.priceV2?.currencyCode || 'USD',
}));
return (
My Shopify Store
);
}
export default App;
`
`
function App() {
const { loading, error, data } = useQuery(GET_PRODUCTS);
const [cart, setCart] = useState([]);
const addToCart = (product) => {
setCart([...cart, { ...product, quantity: 1 }]);
};
if (loading) return
Loading...
;if (error) return
Error: {error.message}
;const products = data.products.edges.map(({ node }) => ({
id: node.id,
title: node.title || 'Unnamed Product',
description: node.description || 'No description available',
image: node.images.edges[0]?.node.src || 'https://via.placeholder.com/150',
price: node.variants.edges[0]?.node.priceV2?.amount || '0.00',
currency: node.variants.edges[0]?.node.priceV2?.currencyCode || 'USD',
}));
return (
My Shopify Store
);
}
export default App;
`
-
What code does it do?:
- Defines a GraphQL query (
GET_PRODUCTS
) to fetch 10 products with their details (ID, title, image, price, etc.). - Uses
useQuery
to run the query when the app loads. - Manages a
cart
state withuseState
to store added products. - Shows a loading message while fetching data or an error if something goes wrong.
- Maps the API data into a simple product list and passes it to
ProductList
andCart
.
- Defines a GraphQL query (
-
Create the Product CardList Component:
- Create a folder
src/components
if it doesn’t exist. - Create
src/components/ProductList.jsx
:
- Create a folder
import React from 'react';
function ProductList({ products, addToCart }) {
return (
<div className="grid grid-cols-3 gap-4">
{products.map((product) => (
<div key={product.id} className="border p-4 rounded-lg shadow-md">
<img src={product.image} alt={product.title} className="w-full h-48 object-cover mb-4" />
<h2 className="text-xl font-semibold">{product.title}</h2>
<p className="text-gray-600">{product.description.slice(0, 100)}...</p>
<p className="text-lg font-bold mt-2">
{product.price} {product.currency}
</p>
<button
onClick={() => addToCart(product)}
className="mt-4 bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
>
Add to Cart
</button>
</div>
))}
</div>
);
}
export default ProductList;
-
What does it do?:
- Takes a list of
products
and anaddToCart
function as props. - Displays each product in a card with an image, title, description (shortened to 100 characters), and price.
- Includes an “Add to Cart” button that calls
addToCart
with the product details.
- Takes a list of
-
Create the Cart Component:
- Create
src/components/Cart.jsx
:
- Create
`
import React from 'react';
function Cart({ cart }) {
const total = cart.reduce((sum, item) => sum + parseFloat(item.price), 0).toFixed(2);
return (
<div className="border p-4 rounded-lg shadow-md">
<h2 className="text-xl font-semibold mb-4">Cart</h2>
{cart.length === 0 ? (
<p className="text-gray-600">Your cart is empty.</p>
) : (
<>
{cart.map((item, index) => (
<div key={index} className="flex justify-between mb-2">
<span>{item.title}</span>
<span>{item.price} {item.currency}</span>
</div>
))}
<hr className="my-4" />
<div className="flex justify-between font-bold">
<span>Total:</span>
<span>{total} {cart[0]?.currency || ''}</span>
</div>
</>
)}
</div>
);
}
export default Cart;
`
-
What does it do?:
- Takes a
cart
array as a prop. - Shows a list of items in the cart with their prices.
- Calculates and displays the total price.
- Displays “Your cart is empty” if the cart is empty.
- Takes a
-
Update the HTML File:
- Replace
index.html
with:
- Replace
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My Shopify Storefront</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
- This sets up the HTML structure and includes Tailwind CSS via CDN.
Step 5: Run and Test Your Storefront
-
Start the Server:
- In your terminal, run:
bash npm run dev
- Open
http://localhost:5173
in your browser.
- In your terminal, run:
-
What You’ll See:
- A header saying “My Shopify Store.”
- A grid of product cards with images, titles, descriptions, prices, and “Add to Cart” buttons.
- A cart on the right showing added items and a total price.
-
Test It Out:
- Click “Add to Cart” on a product. They should appear in the cart.
- If you see “Loading…” or an error, double-check:
- Your Shopify API token and store domain in
main.jsx
. - That your Shopify store has products with images and prices.
- That your internet connection is stable.
- Your Shopify API token and store domain in
Step 6: Deploy Your Storefront
Once your storefront looks good, you can share it online using a hosting service like Vercel or Netlify.
-
Prepare for Deployment:
- Store your Shopify API token in a
.env
file for security:env VITE_SHOPIFY_API_TOKEN=your-storefront-api-token
- Update
main.jsx
to use the environment variable:javascript headers: { 'X-Shopify-Storefront-Access-Token': process.env.VITE_SHOPIFY_API_TOKEN, },
- Store your Shopify API token in a
-
Deploy to Vercel:
- Sign up at vercel.com.
- Install Vercel CLI:
npm install -g vercel
- Run:
bash vercel
- Follow the prompts to link your project and deploy.
- Add your
VITE_SHOPIFY_API_TOKEN
to Vercel’s environment variables in their dashboard.
-
Test Your Live Site:
- Vercel provides a URL (e.g.,
your-app-name.vercel.app
). Open it to see your live storefront!
- Vercel provides a URL (e.g.,
Taking Your Storefront to the Next Level
Your storefront is now functional, but there are ways to make it even better:
- Add Product Pages: Use React Router to create individual product pages.
- Improve the Cart: Allow users to update quantities or remove items.
- Add Checkout: Use Shopify’s checkout API to process payments.
- Polish the Design: Customize Tailwind’s classes or add animations.
- Optimize for Mobile: Test your site on phones and tweak the CSS for responsiveness.
If this feels like a lot, consider reaching out to a Shopify Expert agency to help refine and scale your store. They can handle complex integrations and ensure a professional finish.
Need Help? Hire Experts
Building a custom storefront is a big project, especially if you want advanced features like custom animations or subscriptions. If you’re ready to take your store to the next level, you can Hire dedicated ReactJS developers to bring your vision to life. They can code faster, handle bugs, and add cool features like real-time inventory updates.
Troubleshooting Tips
-
No Products Show Up?
- Check your API token and store domain in
main.jsx
. - Ensure your Shopify store has products with images and prices.
- Look at the browser’s “Console” tab (right-click > Inspect) for errors).
- Check your API token and store domain in
-
Styles Look Weird?
- Make sure Tailwind CSS is included in
index.html
orindex.css
. - Clear your browser cache or try a different browser).
- Make sure Tailwind CSS is included in
-
API Errors?
- Test your Shopify API in GraphiQL to confirm it’s working.
- Verify your API token has Storefront permissions.
Conclusion
You’ve just built a custom Shopify storefront with React.js! You learned how to:
- Set up a Shopify store and Storefront API.
- Create a React project with Tailwind CSS and Vite- Connect to Shopify’s API with Apollo Client.
- Build components for products and a cart to fetch products and manage a cart.
- Deploy your app to Vercel.
This is just the beginning. With practice, you can add more features and make your store stand out!. If you’re feeling stuck or want to go big, a Shopify Expert agency can guide you, or you can Hire dedicated ReactJS developers to supercharge your project. Keep coding, experimenting, and have fun building your dream store!
Top comments (5)
Hi. I have been building a website for a new product launch. And I am newbie. Can you tell me what does Shopify bring on the table? Is it free? Why should I use it instead of normal app? Is the payment gateway automatically integrated in Shopify?
Hey Ruqaiya, to answer more precisely, I'll need to understand the type of the product you are building the website for.
I'll respond to your other questions one by one.
It’s secure (PCI DSS compliant, SSL certificates), scalable (from startups to enterprises), and provides 24/7 support via chat, email, or phone.
Is it free?
No, but I wish it was. The pricing starts at ~$39 USD/month. Offers a 3-day free trial (no credit card required).
The pricing may vary a little based on region. I recommend checking that on official platform for your region. shopify.com/pricing
Why should I use it instead of a normal app?
Because Shopify simplifies online store setup without the need of much coding, unlike general website builders (e.g., Wix, WordPress) that require manual e-commerce setup.
Moreover, Shopify includes built-in tools for inventory, payments, and shipping, plus secure hosting and scalability for your product launch.
Is the payment gateway automatically integrated into Shopify?
Shopify Payments is automatically integrated in supported countries like US, UK, and Canada. Alternatively, you choose from 100+ third-party gateways like Paypal or stripe with easy setup. But there would be some transaction fees for non-Shopify Payments gateways.
I hope I've answered your queries.
Thank you so much for the detailed answer. It helps.
Glad to help!
pretty cool seeing it laid out like this - sticking with new stuff past the first week is tough for me though, you think showing up every day makes the biggest difference or is it more about pushing when things get tricky?