Cart

The shopping cart page with line items, offers, coupon and the order summary.

Framework: TanStack Start

This page is written for TanStack Start, the default and currently supported framework. See what depends on the framework.

The customer sees what they added, can change quantities, apply a coupon or loyalty points, and continue to checkout. Guests and signed-in customers both see it. Customise this route to change how cart lines and the summary look.

URL

PatternExample
/{-$locale}/cart/cart · /ar/cart

The only param is the optional locale (locale prefix). There are no search params.

Try it

This is the cart as the engine renders it, running against the demo store. Switch the language or the width.

/ar/cartOpen
Route
/{-$locale}/cart
This address becomes
  • locale = ar
  • path = /cart

Route file

app/routes/cart.tsx
// @auto-generated
import { createFileRoute } from '@tanstack/react-router';
import { Cart } from '@salla.sa/twilight-theme-engine/routes/cart';
import type { CartPageProps } from '@salla.sa/twilight-theme-engine/routes/cart';
import { CartSkeleton } from '@salla.sa/twilight-theme-engine/skeleton';
import { withHead } from '@salla.sa/twilight-theme-engine/tanstack';

export const Route = createFileRoute('/{-$locale}/cart')({
  loader: ({ params }): Promise<CartPageProps> => Cart.loader({ locale: params.locale }),
  head: withHead(Cart),
  pendingComponent: () => <CartSkeleton />,
  component: CartComponent,
});

function CartComponent() {
  const data: CartPageProps = Route.useLoaderData();
  return <Cart.Component {...data} />;
}

Delete the // @auto-generated line to own the file.

A customised version

Same engine loader, head and skeleton, with your own page component. CartPage here is a component you write in app/components/cart/CartPage.tsx; it receives the loader data (CartPageProps). To use your own file for /cart, point the path at it from app/routes.ts (see Fork a built-in route).

app/routes/cart-page.tsx
import { createFileRoute } from '@tanstack/react-router';
import { Cart } from '@salla.sa/twilight-theme-engine/routes/cart';
import type { CartPageProps } from '@salla.sa/twilight-theme-engine/routes/cart';
import { CartSkeleton } from '@salla.sa/twilight-theme-engine/skeleton';
import { withHead } from '@salla.sa/twilight-theme-engine/tanstack';
import { CartPage } from '../components/cart/CartPage';

export const Route = createFileRoute('/{-$locale}/cart')({
  loader: ({ params }): Promise<CartPageProps> => Cart.loader({ locale: params.locale }),
  head: withHead(Cart),
  pendingComponent: () => <CartSkeleton />,
  component: CartComponent,
});

function CartComponent() {
  const data: CartPageProps = Route.useLoaderData();
  return <CartPage {...data} />;
}

What it loads

The loader returns only { page: { slug, title } }. The cart itself is not loaded on the server, because the cart id lives in the browser. After the page mounts, the component reads the current cart id from the Salla SDK, fetches that cart, and shows CartSkeleton until it has it. Your own component does the same if it needs cart data; for live updates see React to cart events.

Head and SEO

Title is the translated "Cart", plus hreflang links. There is no description, canonical or Open Graph tag.

Edge cases

  • Empty cart. The page shows "Your cart is empty" with a link home.
  • Skeleton in the server HTML. The server always sends the skeleton for /cart, since the cart is browser-only. This is expected.
  • Extending the loader. Cart.loader takes an optional extend callback, but only a synchronous result is merged; an async one is ignored.
  • Hook slots. cart:start, cart:items.start, cart:items.end and cart:end let you add content without forking (hook slots).

See also

On this page