--- title: Render a cart from client side description: Set up the cart so that it renders from the client side. source_url: html: >- https://shopify.dev/docs/storefronts/headless/hydrogen/cart/render-client-side md: >- https://shopify.dev/docs/storefronts/headless/hydrogen/cart/render-client-side.md --- ExpandOn this page * [Step 1: Add a loader on your cart route](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/render-client-side.md#step-1-add-a-loader-on-your-cart-route) * [Step 2: Create a provider and a hook for getting the cart data](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/render-client-side.md#step-2-create-a-provider-and-a-hook-for-getting-the-cart-data) * [Step 3: Include your Cart​Provider in your root](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/render-client-side.md#step-3-include-your-cartprovider-in-your-root) * [Step 4: Get cart content with your use​Cart hook](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/render-client-side.md#step-4-get-cart-content-with-your-usecart-hook) # Render a cart from client side Note This guide might not be compatible with features introduced in Hydrogen version 2025-05 and above. Check the latest [documentation](https://shopify.dev/docs/api/hydrogen) if you encounter any issues. Returning cart data, along with other data that builds a page, from a Remix loader server-renders the cart. However, if you want to turn on cache control for a page, then the cart shouldn't be server-rendered because carts are user-specific and should never be shared across different user sessions. The cache control header structure is `public, max-age=1, stale-while-revalidate=9`. There are many other [cache-control configurations](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) available, but this guide focuses on the `private` and `public` modes: * `private`: Only the client browser is allowed to cache the request. No servers are allowed to cache the content. `private` mode is helpful for user account pages, which are relatively static in nature but shouldn't have public servers caching the request due to personalized or sensitive content. * `public`: Public servers like Oxygen, or any other CDNs, are allowed to cache the request. The same content can be reused with multiple users requesting the same page. The content shouldn't contain personalized or sensitive content. To set `public` cache control on your loader data, you'll need to convert your cart to render from the client side. ### Benefits of turning on cache control * Static pages like blogs or articles can be cached longer * You can expect cached pages to result in smaller response times compared to non-cached pages if they're served from Oxygen ### Trade offs of turning on cache control * Expect delayed UI updates for personalized content. For example, if you have a cart icon that displays the number of items in cart, then expect updates to this value to be delayed during a full page load. The delay results from loading the required JavaScript bundles and making a request to get the cart data. * UI elements that rely on the client-side cart data fetch, such as the checkout button, aren't functional until the page finishes loading, JavaScript executes, a request to the server returns with cart data, and the client re-renders. * Performance metric [time to interactive (TTI)](https://developer.chrome.com/en/docs/lighthouse/performance/interactive/) will be longer due to the delayed cart's request. *** ## Step 1: Add a loader on your cart route Create a dedicated route to get a user's cart data. The route also serves as an API. You can get a user's cart by making a fetcher request to `/cart`. ## File ## /app/routes/api.cart.jsx ##### JavaScript ```jsx import {json} from '@shopify/remix-oxygen'; import {useLoaderData} from '@remix-run/react'; export async function loader({context}) { const {cart} = context; return json(await cart.get()); } export default function CartRoute() { const cart = useLoaderData(); return ( ); } ``` ##### TypeScript ```jsx import {json, type LoaderArgs} from '@shopify/remix-oxygen'; import {useLoaderData} from '@remix-run/react'; export async function loader({context}: LoaderArgs) { const {cart} = context; return json(await cart.get()); } export default function CartRoute() { const cart = useLoaderData(); return ( ); } ``` *** ## Step 2: Create a provider and a hook for getting the cart data Create the `` and `useCart` hook to enable read access to a user's cart across the app: ## File ## /app/components/CartProvider.jsx ##### JavaScript ```jsx import {createContext, useContext, useEffect} from "react"; import {Cart} from '@shopify/hydrogen-react/storefront-api-types'; import {useFetcher} from "@remix-run/react"; const CartContext = createContext(undefined); export function CartProvider({children}) { const fetcher = useFetcher(); useEffect(() => { fetcher.load('/api/cart'); }, []); return {children}; } export function useCart() { return useContext(CartContext); } ``` ##### TypeScript ```jsx import {createContext, useContext, useEffect} from "react"; import {Cart} from '@shopify/hydrogen-react/storefront-api-types'; import {useFetcher} from "@remix-run/react"; const CartContext = createContext(undefined); export function CartProvider({children}: {children: React.ReactNode}) { const fetcher = useFetcher(); useEffect(() => { if (fetcher.data || fetcher.state === 'loading') return; fetcher.load('/api/cart'); }, [fetcher]); return {children}; } export function useCart() { return useContext(CartContext); } ``` *** ## Step 3: Include your `CartProvider` in your root Include the `CartProvider` component in your root layout so that your `useCart` hook is available in the entire app. ## File ## /app/root.jsx ##### JavaScript ```jsx import {CartProvider} from './components/CartProvider'; export default function App() { return ( ); } ``` ##### TypeScript ```jsx import {CartProvider} from './components/CartProvider'; export default function App() { return ( ); } ``` *** ## Step 4: Get cart content with your `useCart` hook Access a user's cart data to do client-side UI rendering from anywhere in your app by using the `useCart` hook within the `` component. ## File ## /app/components/Layout.jsx ##### JavaScript ```jsx import {useCart} from './CartProvider'; function CartCount({ isHome, openCart, }: { isHome: boolean; openCart: () => void; }) { const cart = useCart(); return ( ); } ``` ##### TypeScript ```jsx import {useCart} from './CartProvider'; function CartCount({ isHome, openCart, }: { isHome: boolean; openCart: () => void; }) { const cart = useCart(); return ( ); } ``` If you provide cart data in any Remix loaders, then make sure to remove them. ## File ## /app/root.jsx ##### JavaScript ```jsx export async function loader({context}) { const {storefront} = context; return defer({ selectedLocale: storefront.i18n, // cart: cart.get(), }); } ``` ##### TypeScript ```jsx export async function loader({context}: LoaderArgs) { const {storefront} = context; return defer({ selectedLocale: storefront.i18n, // cart: cart.get(), }); } ``` *** * [Step 1: Add a loader on your cart route](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/render-client-side.md#step-1-add-a-loader-on-your-cart-route) * [Step 2: Create a provider and a hook for getting the cart data](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/render-client-side.md#step-2-create-a-provider-and-a-hook-for-getting-the-cart-data) * [Step 3: Include your Cart​Provider in your root](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/render-client-side.md#step-3-include-your-cartprovider-in-your-root) * [Step 4: Get cart content with your use​Cart hook](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/render-client-side.md#step-4-get-cart-content-with-your-usecart-hook)