Storefronts
Design a shop in PopCraft and publish it as a store that sells — a Next.js Commerce store on Vercel with your Shopify products, cart and checkout — or export it for a Next.js Commerce store. The Ecommerce plugin adds the Shopify catalogue, store setup and a Shopify theme.
Design a shop once, bound to a store's products, cart and menu, and publish it as a store that sells, or export it to whichever store runs it. Export storefront… has two targets, and plugins add more (the Ecommerce plugin adds a Shopify theme):
| Target | What you get | Where it runs |
|---|---|---|
| Next.js Commerce store | The whole store: Next.js Commerce with a page per screen, drawn by the design | Vercel, or any Next.js host, with a Shopify store's domain and Storefront token |
| Next.js Commerce components | A React component per page, its props the store's data and server actions | A Next.js Commerce store you already run |
The store keeps what it already does well (the catalogue, the cart, checkout, search); PopCraft supplies the design: its layout at every breakpoint, its type, colours and motion. A designer changes the shop in PopCraft, exports it again, and the store picks the new design up without anyone rewriting a page.
Description
The Fieldwork storefront template on the canvas: its home, search, product and cart pages, drawn with the shop's sample products. The command palette runs Export as storefront components… and a zip downloads with a React component per page — HomePage, SearchPage, ProductPage and CartPage — whose props are the store's products, cart and menu and its add-to-cart and checkout actions.
Publish a store
A storefront design publishes as a store that sells. Open Publish (or press ⌘K and run Publish as a store): the Store section says which Shopify store it sells from and where it is hosted, and Deploy store sends it.
- Choose the Shopify store in the Ecommerce plugin. It keeps the store's address and
public Storefront token in the file's site environment (
SHOPIFY_STORE_DOMAIN,SHOPIFY_STOREFRONT_ACCESS_TOKEN). - Connect Vercel in Integrations.
- Deploy store. PopCraft builds the whole Next.js Commerce store from the design, makes a Vercel project for it (the first time), sets the site environment as the project's encrypted environment, and deploys it. It is live in a minute or two, at the project's address.
The store is Next.js Commerce: the products, prices and pictures are your Shopify store's, add to cart and the cart are real, and Check out goes to Shopify's checkout. Its menu is your store's main menu (Online Store › Navigation), or every product and its first categories when there is none. Change the design and deploy again: the store picks up the new design. Add your own domain to the project in Vercel.
The Ecommerce plugin
Shopify is not built into PopCraft: the Ecommerce plugin brings it, from Marketplace › Plugins. It opens as a tab on the side of the editor:
- Store. Your Shopify store's
.myshopify.comaddress and its public Storefront access token (Shopify admin › Sales channels › Headless › your storefront › Storefront API). It keeps them in the file, so publishing and everyone who opens the file use the same store. - Catalogue. The store's products as pictures, filtered by category, a product or a search, sorted and limited. Select layers on the page and click a product to link them to it: they show that product (its picture, title and price, and a product card's properties), and stay linked to it when it changes in your store. + places just its picture. Use in the design fills the design's products with the ones shown, so the canvas shows what the store really sells; products already in the design keep their place, so linked layers stay linked.
- Make it a store. Adds the products, categories, cart, cart lines and menu collections a store needs, with sample records, to any design.
- Checklist. What the design still needs to sell (a product list, a product page, add to cart, the cart, checkout), each with the layer to fix selected for you, and Fix where the plugin can do it: a store form gets the fields it sends without your adding hidden fields by hand.
- Shopify theme. Export › Shopify theme writes an Online Store 2.0 theme of the design to upload in your store's admin (Online Store › Themes › Add theme), running on Shopify with its own cart and checkout.
Start from a storefront template
Nine templates are whole stores, each in a world of its own, their pages matching a store's routes:
| Template | The store | How it opens and moves |
|---|---|---|
| Fieldwork storefront | Workwear: light, a split hero | Rises in, calm |
| Kiln storefront | A ceramics studio: a serif, a full-width studio picture | Rises in, calm |
| Ode product launch | One kettle made the hero, dark and quiet | Rises in; its accessories and specs under it |
| Static streetwear drop | Black and acid lime, a poster over a night street | A ticker for the drop; pops, slides and bounces |
| Bloom skincare store | Blush and plum, a soft serif, framed cards | Its products float over a centred hero; blurs in |
| Summit outdoor store | A mountain poster, condensed type | A ticker for the sale; drops and pops in |
| Marginalia bookshop | Cream and ink, a literary serif, tall covers | The headline types itself; the picture wipes in |
| Greenhouse plant shop | Sage, round framed cards | Its plants float over a centred hero; blurs in |
| Circuit audio store | Dark navy and electric blue, mono details | Pops in; its pictures drift |
| Screen | Route | What it shows |
|---|---|---|
| Home | / | The hero, three featured products, the store's story, a carousel of every product, what is new, the newsletter (a launch: the product, bought from there) |
| Search | /search | The search field, the categories and every product |
| Category | /search/[handle] | One category: its title and words, the others as chips, its products |
| Product | /product/[handle] | One product: its picture, price, description, add to cart, and related products |
| Cart | /cart | A line per product (quantity, price, remove), the totals and checkout |
Their products, categories, cart and menu are collections with a commerce schema. On the canvas they show the shop's sample products, or the Ecommerce plugin's real ones from your store. Exported, each becomes a prop the store fills with its own data.
Bind your own design
Any design can be a storefront. You need three things:
-
A collection with a schema. In Collections, make a collection and set Stands for:
commerce.product: title, handle, URL, description, price, max price, image, image alt, available, variant ID and tags.commerce.collection: title, handle, URL and description.commerce.cartLine: title, variant, URL, image, quantity, price and merchandise ID.commerce.cart: count, subtotal, taxes, total and checkout URL. It has one record, shown through a list of one.commerce.menu: title and URL.
The schema's fields are made for you; add sample records to design with, or fill it with your store's products in the Ecommerce plugin, whose Make it a store makes all five at once.
-
Lists and picked products. A frame that repeats over the collection draws its words and pictures from each record. A layer can instead show one product you pick in the Design panel's Data section (or by clicking it in the Ecommerce plugin): published, it shows the store's product with that handle. What a layer shows of its product is bound in Data: a text's words, a picture, or a component instance's properties. The templates' cards are a Product card component whose Image, Title and Price are bound to the product's image, title and price. A screen whose page is one per record of a product collection is a product's page. A link from a card to that screen goes to the product it is drawn for.
-
Forms that do a store's job. Set a form's Sending it to a storefront action:
Action What the form sends The prop Adds the product to the cart merchandiseId(a hidden field,{{item.variant_id}})onAddToCartChanges a cart line's quantity merchandiseIdandquantityonUpdateCartLineRemoves a line from the cart merchandiseId({{item.merchandise_id}})onRemoveCartLineGoes to checkout nothing onCheckoutSearches the store qonSearch
Next.js Commerce components
What is in the zip
| Path | What it is |
|---|---|
components/popcraft/HomePage.tsx, ProductPage.tsx, … | A component per screen, named for it. Its props are the lists it draws, the record it is about, and the forms it sends |
components/popcraft/index.ts | Every component and its props type |
public/popcraft/assets/ | The pictures the design draws itself; product images come from the store |
A component looks like this:
export interface ProductPageProps {
/** The product this page is about. */
product?: Product
/** Products (the related products under it). */
products?: Product[]
cart?: Cart
menu?: Menu[]
onAddToCart?: (formData: FormData) => void | Promise<void>
}
export function ProductPage({ product, cart, products, menu, onAddToCart }: ProductPageProps = {}) { … }A list's prop is named for its collection (products, cartLines); two lists of one collection share it (the
home page's featured and new products both draw from products, each its own slice). The types are Next.js Commerce's own (Product, Cart, CartItem, Collection, Menu), from
@popcraft/runtime/commerce, so a store passes its data in unchanged. With no data, a component draws the design's
sample records, so a component renders on its own in a storybook or a test. Left out means samples, so a store passes what it has
even when it is empty: cartLines={[]}, and an empty cart rather than none.
Use them in a Next.js Commerce store
Install the runtime, export the components into the store and render them from its pages:
npm install @popcraft/runtime// app/product/[handle]/page.tsx
import { getProduct, getProductRecommendations, getCart, getMenu } from 'lib/shopify'
import { addItem } from 'components/cart/actions'
import { ProductPage } from 'components/popcraft'
export default async function Page({ params }: { params: Promise<{ handle: string }> }) {
const { handle } = await params
const product = await getProduct(handle)
if (!product) return notFound()
const [related, cart, menu] = await Promise.all([getProductRecommendations(product.id), getCart(), getMenu('next-js-frontend-footer-menu')])
async function add(formData: FormData) {
'use server'
await addItem(null, String(formData.get('merchandiseId')))
}
return <ProductPage product={product} products={related} cart={cart} menu={menu} onAddToCart={add} />
}getpopcraft/examples › commerce is a whole store made
this way: Next.js Commerce with its pages rendering a PopCraft design, and npm run design:sync to export again.
From the command line
popcraft storefront shop.popcraft --target next-commerce --out . # components, into a Next.js Commerce store
popcraft storefront shop.popcraft --target next-commerce-store --out shop # the whole store--page picks the page, --styling tailwind writes Tailwind classes and --dir another folder for the
components. From the CLI, pictures only the canvas can draw (a shader, a blur) are left as a comment; export from the
app to have them drawn.
More targets from plugins
A plugin can write a store PopCraft does not: BigCommerce's Stencil, WooCommerce, a headless CMS. It contributes an
exporter and reads the open page's storefront with popcraft.getStorefront(): each page's HTML and
stylesheet with the store's data marked rather than filled, and the collections it reads.
const store = await popcraft.getStorefront()
// store.pages[i].html: the page, its fields marked {{page.title}} (the record a page is about) and {{item.price}}
// (inside a list), each list between <!-- pc:each list="Products" schema="commerce.product" as="item" limit="4" -->
// and <!-- pc:end -->, each storefront form with data-pc-action="addToCart" (removeCartLine, checkout, search…)
// store.collections: each with its schema, its fields' keys and its sample records
const files = toMyStoreTemplates(store) // your platform's templates
await popcraft.saveExport({ name: 'theme.zip', bytes: zip(files) })The fields' keys are the same in every target: title, price, image, url, variant_id for a product, and
so on for the cart, its lines, categories and the menu.
What stays with the store
Variant pickers, the cart's optimistic updates, search's sorting and filtering, accounts and checkout are the store's, in every target. The design draws the first available variant's ID into its add-to-cart form; a store that sells options renders Next.js Commerce's variant selector beside the component, or binds its own.