Template Types Reference

Templates are React components that you can directly edit to add or change a given route's (e.g., page, product, collection...) structure and layout.

Each template renders the sections added in the Customizer or Pack Admin with the <RenderSections> component from @pack/react.

The examples below are trimmed from the Blueprint's routes. Their loader data types (Page, BlogPage, ArticlePage, ProductWithInitialGrouping, SelectedVariant) come from the Blueprint's ~/lib/types, and useProductWithGrouping from its ~/hooks. The collection example's ActiveFilterValue is in ~/components/Collection/CollectionFilters/CollectionFilters.types, and CollectionType is Shopify's Collection type from @shopify/hydrogen/storefront-api-types.

Available Types

You can find all available template types inside your storefront's Github repository in the /app/routes directory.

  • Home — renders on / home page visits
  • Page — renders on /pages/:handle visits
  • Blog — renders on /blogs/:handle visits
  • Article — renders on /articles/:handle visits
  • Product — renders on /products/:handle visits
  • Collection — renders on /collections/:handle visits
  • Account — renders on /account/:subroute visits
  • 404 — renders on invalid-routes visits

Default Templates

When you create a store, you’ll find several templates that are already created for you by default. Let’s review each template.

Home

This template will be used for your storefront's homepage.

Page

This template will be used for all pages that follow the /pages/ route in your storefront.

// app/routes/($locale).pages.$handle.tsx
export default function PageRoute() {
  const { page } = useLoaderData<{ page: Page }>();

  return (
    <div data-comp="PageRoute">
      <RenderSections content={page} />
    </div>
  );
}

Blog

This template will be used for all blog pages that follow the /blogs/ route in your storefront.

// app/routes/($locale).blogs.$handle.tsx
export default function BlogRoute() {
  const { blog } = useLoaderData<{ blog: BlogPage }>();

  return (
    <div data-comp="BlogRoute">
      <RenderSections content={blog} />
    </div>
  );
}

Article

This template will be used for all article pages in your storefront. The Blueprint renders it from two routes, /articles/:handle and /blogs/:blogHandle/:handle.

// app/routes/($locale).articles.$handle.tsx
// and app/routes/($locale).blogs.$blogHandle.$handle.tsx
export default function ArticleRoute() {
  const { article } = useLoaderData<{ article: ArticlePage }>();

  return (
    <div className="py-contained" data-comp="ArticleRoute">
      <section data-comp="article-header">
        {/* author, date, title, and category */}
      </section>

      <RenderSections content={article} />
    </div>
  );
}

Product

This template will be used for all product pages that follow the /products/:handle route in your storefront.

// app/routes/($locale).products.$handle.tsx
export default function ProductRoute() {
  const {
    product: initialProduct,
    productPage,
    selectedVariant,
  } = useLoaderData<{
    product: ProductWithInitialGrouping;
    productPage?: Page;
    selectedVariant?: SelectedVariant;
  }>();
  // Adds the product's Pack grouping: options and variants across the grouped products
  const product = useProductWithGrouping(initialProduct);

  return (
    <ProductProvider
      data={product}
      initialVariantId={selectedVariant?.id || null}
    >
      <div data-comp="ProductRoute">
        <Product product={product} initialSelectedVariant={selectedVariant} />

        {productPage && <RenderSections content={productPage} />}
      </div>

      {/* The Blueprint also renders <Analytics.ProductView> here. See the route implementation guide. */}
    </ProductProvider>
  );
}

Collection

This template will be used for all collection pages that follow the /collections/:handle route in your storefront.

// app/routes/($locale).collections.$handle.tsx
export default function CollectionRoute() {
  const { activeFilterValues, collection, collectionPage } = useLoaderData<{
    activeFilterValues: ActiveFilterValue[];
    collection: CollectionType;
    collectionPage?: Page;
  }>();

  // Hide the default collection heading when the page has a hero or banner section
  const hasVisibleHeroSection = !!collectionPage?.sections.nodes.some(
    ({ data }: any) => ['hero', 'banner'].includes(data?._template),
  );

  return (
    <div data-comp="CollectionRoute">
      {collectionPage && <RenderSections content={collectionPage} />}

      <section data-comp="collection">
        <Collection
          activeFilterValues={activeFilterValues}
          collection={collection}
          showHeading={!hasVisibleHeroSection}
          title={collectionPage?.title}
        />
      </section>

      {/* The Blueprint also renders <Analytics.CollectionView> here. See the route implementation guide. */}
    </div>
  );
}

Account

The account template comprises multiple other sub-templates for routes such as sign-in, order history, address book, payment methods, and more.

All available sub-templates for the account template can be found in the /app/routes directory.

404

This template will be used for all 404 pages in your storefront.

The Blueprint's catch-all route throws a 404 from its loader, so the route itself renders nothing:

// app/routes/$.tsx
export async function loader({ request }: Route.LoaderArgs) {
  throw new Response(`${new URL(request.url).pathname} not found`, {
    status: 404,
  });
}

export default function Route404() {
  return null;
}

The root route's ErrorBoundary then renders the 404 page. In the Blueprint, that page isn't built from sections. It shows a banner from the Not Found (404) group in your site settings, which you edit in the Customizer.

Guides

Templates

Learn more about templates

Read more

Sections

Learn more about sections

Read more

Localhost Setup

Learn how to set up your localhost

Read more

Was this page helpful?