---
title: Dynamic content with metaobjects in Hydrogen
description: Build a flexible CMS using Shopify metaobjects for dynamic content sections
source_url:
html: 'https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects'
md: >-
https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md
---
ExpandOn this page
* [Requirements](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#requirements)
* [Ingredients](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#ingredients)
* [Step 1: Document the metaobjects CMS](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-1-document-the-metaobjects-cms)
* [Step 2: Add product fragment for sections](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-2-add-product-fragment-for-sections)
* [Step 3: Create edit route component](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-3-create-edit-route-component)
* [Step 4: Expose store subdomain](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-4-expose-store-subdomain)
* [Step 5: Build store profile route](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-5-build-store-profile-route)
* [Step 6: Add metaobjects to homepage](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-6-add-metaobjects-to-homepage)
* [Step 7: Display all stores](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-7-display-all-stores)
* [Step 8: Install rich text dependencies](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-8-install-rich-text-dependencies)
* [Step 9: Create route content component](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-9-create-route-content-component)
* [Step 10: Build featured collections section](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-10-build-featured-collections-section)
* [Step 11: Build featured products section](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-11-build-featured-products-section)
* [Step 12: Build hero banner section](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-12-build-hero-banner-section)
* [Step 13: Build store profile section](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-13-build-store-profile-section)
* [Step 14: Build stores grid section](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-14-build-stores-grid-section)
* [Step 15: Create section renderer](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-15-create-section-renderer)
* [Step 16: Add section parsing utility](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-16-add-section-parsing-utility)
* [Step 17: Add setup guide](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-17-add-setup-guide)
* [Step 18: Link field screenshot](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-18-link-field-screenshot)
* [Step 19: Featured collections definition screenshot](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-19-featured-collections-definition-screenshot)
* [Step 20: Featured products definition screenshot](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-20-featured-products-definition-screenshot)
* [Step 21: Hero section definition screenshot](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-21-hero-section-definition-screenshot)
* [Step 22: Rich text section definition screenshot](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-22-rich-text-section-definition-screenshot)
* [Step 23: Store profile definition screenshot](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-23-store-profile-definition-screenshot)
* [Step 24: Stores grid definition screenshot](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-24-stores-grid-definition-screenshot)
* [Step 25: Store definition screenshot](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-25-store-definition-screenshot)
* [Step 26: Definitions list screenshot](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-26-definitions-list-screenshot)
* [Step 27: Route definition screenshot](https://shopify.dev/docs/storefronts/headless/hydrogen/cookbook/metaobjects.md#step-27-route-definition-screenshot)
# Dynamic content with metaobjects in Hydrogen
This recipe creates a content management system using Shopify metaobjects. It lets you create and manage dynamic content sections through your Shopify admin, providing a flexible way to build pages with reusable components.
Key features:
* Dynamic route-based content rendering
* Modular section components (Hero, Featured Products, Featured Collections, Stores)
* Content editing capabilities with direct links to Shopify admin
* Rich text support with Slate editor
* Comprehensive documentation with visual guides
This recipe includes example section components that can be customized or extended to match your specific content needs. See the included `guides/metaobjects/README.md` file for detailed setup instructions.
Note
You need to create the metaobject definitions in your Shopify admin before using this recipe. Each section component has a one-to-one relationship with a metaobject definition.
***
## Requirements
* Basic understanding of Shopify metaobjects
* Shopify store with metaobjects enabled (Shopify Plus or development store)
* Metaobject definitions created in your Shopify admin
* Environment variable: PUBLIC\_STORE\_DOMAIN (your store's admin domain)
***
## Ingredients
*New files added to the template by this recipe.*
| File | Description |
| - | - |
| [app/components/EditRoute.tsx](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/app/components/EditRoute.tsx) | |
| [app/routes/stores.$name.tsx](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/app/routes/stores.$name.tsx) | |
| [app/routes/stores.\_index.tsx](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/app/routes/stores._index.tsx) | |
| [app/sections/RouteContent.tsx](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/app/sections/RouteContent.tsx) | |
| [app/sections/SectionFeaturedCollections.tsx](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/app/sections/SectionFeaturedCollections.tsx) | |
| [app/sections/SectionFeaturedProducts.tsx](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/app/sections/SectionFeaturedProducts.tsx) | |
| [app/sections/SectionHero.tsx](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/app/sections/SectionHero.tsx) | |
| [app/sections/SectionStoreProfile.tsx](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/app/sections/SectionStoreProfile.tsx) | |
| [app/sections/SectionStores.tsx](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/app/sections/SectionStores.tsx) | |
| [app/sections/Sections.tsx](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/app/sections/Sections.tsx) | |
| [app/utils/parseSection.ts](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/app/utils/parseSection.ts) | |
| [guides/metaobjects/README.md](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/guides/metaobjects/README.md) | |
| [guides/metaobjects/images/definition\_link.png](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/guides/metaobjects/images/definition_link.png) | |
| [guides/metaobjects/images/definition\_section\_featured\_collections.png](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/guides/metaobjects/images/definition_section_featured_collections.png) | |
| [guides/metaobjects/images/definition\_section\_featured\_products.png](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/guides/metaobjects/images/definition_section_featured_products.png) | |
| [guides/metaobjects/images/definition\_section\_hero.png](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/guides/metaobjects/images/definition_section_hero.png) | |
| [guides/metaobjects/images/definition\_section\_rich\_text.png](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/guides/metaobjects/images/definition_section_rich_text.png) | |
| [guides/metaobjects/images/definition\_section\_store\_profile.png](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/guides/metaobjects/images/definition_section_store_profile.png) | |
| [guides/metaobjects/images/definition\_section\_stores\_grid.png](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/guides/metaobjects/images/definition_section_stores_grid.png) | |
| [guides/metaobjects/images/definition\_store.png](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/guides/metaobjects/images/definition_store.png) | |
| [guides/metaobjects/images/definitions\_list.png](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/guides/metaobjects/images/definitions_list.png) | |
| [guides/metaobjects/images/definiton\_route.png](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/guides/metaobjects/images/definiton_route.png) | |
***
## Step 1: Document the metaobjects CMS
Update the README file with metaobjects CMS documentation and an architecture overview.
#### File: [README.md](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/templates/skeleton/README.md) ([patch](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/patches/README.md.db10ed.patch))
## File
````diff
@@ -1,6 +1,8 @@
-# Hydrogen template: Skeleton
+# Hydrogen template: Metaobjects as CMS
-Hydrogen is Shopify’s stack for headless commerce. Hydrogen is designed to dovetail with [Remix](https://remix.run/), Shopify’s full stack web framework. This template contains a **minimal setup** of components, queries and tooling to get started with Hydrogen.
+This Hydrogen template demonstrates how to use Shopify Metaobjects as a content management system (CMS). Hydrogen is Shopify's stack for headless commerce, designed to work with [Remix](https://remix.run/), Shopify's full stack web framework.
+
+This template shows how to create a flexible, section-based content architecture using Shopify's native Metaobjects, allowing merchants to manage content directly from the Shopify admin without external CMS dependencies.
[Check out Hydrogen docs](https://shopify.dev/custom-storefronts/hydrogen)
[Get familiar with Remix](https://remix.run/docs/en/v1)
@@ -16,18 +18,60 @@ Hydrogen is Shopify’s stack for headless commerce. Hydrogen is designed to dov
- Prettier
- GraphQL generator
- TypeScript and JavaScript flavors
-- Minimal setup of components and routes
+- **Metaobjects-based CMS architecture**
+- **Dynamic section rendering system**
+- **Content management through Shopify admin**
+
+## Metaobjects Architecture
+
+This template implements a hierarchical content structure:
+
+```
+Route (Metaobject)
+ └── Sections (References)
+ ├── SectionHero
+ ├── SectionFeaturedProducts
+ ├── SectionFeaturedCollections
+ ├── SectionStoreProfile
+ └── SectionStoreGrid
+```
+
+### Key Features
+
+- **Route-based content**: Each route can have its own set of sections
+- **Reusable sections**: Create once, use across multiple routes
+- **Type-safe**: Full TypeScript support with generated types
+- **Merchant-friendly**: Content managed directly in Shopify admin
+- **Extensible**: Easy to add new section types
## Getting started
**Requirements:**
- Node.js version 18.0.0 or higher
+- Shopify store with Metaobjects enabled
+- Metaobject definitions created in Shopify admin
```bash
npm create @shopify/hydrogen@latest
```
+## Setting up Metaobjects
+
+1. **Create Metaobject definitions** in your Shopify admin:
+ - Navigate to Settings → Custom data → Metaobjects
+ - Create definitions for Route, SectionHero, SectionFeaturedProducts, etc.
+ - See `guides/metaobjects/README.md` for detailed field configurations
+
+2. **Create content entries**:
+ - Add Route entries for pages you want to manage
+ - Create Section entries and link them to Routes
+ - Configure section content and references
+
+3. **Query and render**:
+ - Routes automatically query their associated sections
+ - Sections component handles dynamic rendering based on type
+
## Building for production
```bash
@@ -40,6 +84,21 @@ npm run build
npm run dev
```
+## Creating New Sections
+
+1. Define the Metaobject in Shopify admin
+2. Create a React component in `app/sections/`
+3. Add the GraphQL fragment for querying
+4. Register in the Sections component switch statement
+
+Example:
+```tsx
+export function SectionExample(props: SectionExampleFragment) {
+ const section = parseSection<...>(props);
+ return ...;
+}
+```
+
## Setup for using Customer Account API (`/account` section)
-Follow step 1 and 2 of
+Follow step 1 and 2 of
\ No newline at end of file
````
***
## Step 2: Add product fragment for sections
Add RECOMMENDED\_PRODUCT\_FRAGMENT for displaying product collections in metaobject sections.
#### File: [fragments.ts](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/templates/skeleton/app/lib/fragments.ts) ([patch](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/patches/fragments.ts.026109.patch))
```diff
@@ -232,3 +232,25 @@ export const FOOTER_QUERY = `#graphql
}
${MENU_FRAGMENT}
` as const;
+
+// @description Fragment for recommended products needed by ProductItem component
+export const RECOMMENDED_PRODUCT_FRAGMENT = `#graphql
+ fragment RecommendedProduct on Product {
+ id
+ title
+ handle
+ priceRange {
+ minVariantPrice {
+ amount
+ currencyCode
+ }
+ }
+ featuredImage {
+ id
+ url
+ altText
+ width
+ height
+ }
+ }
+` as const;
```
***
## Step 3: Create edit route component
Add the edit route component for managing metaobject-based content in development.
#### File: [EditRoute.tsx](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/app/components/EditRoute.tsx)
## File
```tsx
import {useState, useEffect} from 'react';
import {Link, useMatches} from 'react-router';
/**
* Displays an `Edit Route` button in the top right corner of the page
* This button opens a new tab that let's you easily edit the metaobject entry in the Shopify Admin
* This is only display when in development or when in preview branch deployment
*/
export function EditRoute({routeId}: {routeId: string}) {
const [url, setUrl] = useState(null);
const [root] = useMatches();
// @ts-expect-error data might not have publicStoreSubdomain
const publicStoreSubdomain = root?.data?.publicStoreSubdomain;
useEffect(() => {
setUrl(new URL(window.location.href));
}, []);
if (!url || !publicStoreSubdomain) return null;
const isDev =
url.hostname.includes('localhost') || url.hostname.includes('127.0.0.1');
const isPreview = url.hostname.includes('preview');
const legacyId = routeId.split('/').pop();
const adminEditUrl = `https://admin.shopify.com/store/${publicStoreSubdomain}/content/entries/route/${legacyId}`;
const shouldShowEditLink = isDev || isPreview;
if (!shouldShowEditLink) return null;
return (
Edit Route
);
}
```
***
## Step 4: Expose store subdomain
Expose the public store subdomain for metaobject queries and content management.
#### File: [root.tsx](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/templates/skeleton/app/root.tsx) ([patch](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/patches/root.tsx.5e9998.patch))
```diff
@@ -90,6 +90,8 @@ export async function loader(args: Route.LoaderArgs) {
country: args.context.storefront.i18n.country,
language: args.context.storefront.i18n.language,
},
+ // @description Add public store subdomain for metaobjects
+ publictoreSubdomain: args.context.env.PUBLIC_STORE_DOMAIN,
};
}
```
***
## Step 5: Build store profile route
Add a dynamic store profile route for displaying store-specific metaobject content.
#### File: [stores.$name.tsx](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/app/routes/stores.$name.tsx)
## File
```tsx
import {useLoaderData} from 'react-router';
import type {Route} from './+types/stores.$name';
// 1. Add metaobject content imports
import {ROUTE_CONTENT_QUERY, RouteContent} from '~/sections/RouteContent';
export const meta: Route.MetaFunction = () => {
return [{title: 'Hydrogen | Home'}];
};
export async function loader(args: Route.LoaderArgs) {
// Start fetching non-critical data without blocking time to first byte
const deferredData = loadDeferredData(args);
// Await the critical data required to render initial state of the page
const criticalData = await loadCriticalData(args);
return {...deferredData, ...criticalData};
}
/**
* Load data necessary for rendering content above the fold. This is the critical data
* needed to render the page. If it's unavailable, the whole page should 400 or 500 error.
*/
async function loadCriticalData({context, params}: Route.LoaderArgs) {
const {storefront} = context;
const {name} = params;
// 2. Query for the route's content metaobject
const [{route}] = await Promise.all([
storefront.query(ROUTE_CONTENT_QUERY, {
variables: {handle: `route-${name}`},
}),
// Add other queries here, so that they are loaded in parallel
]);
return {route};
}
/**
* Load data for rendering content below the fold. This data is deferred and will be
* fetched after the initial page load. If it's unavailable, the page should still 200.
* Make sure to not throw any errors here, as it will cause the page to 500.
*/
function loadDeferredData({context}: Route.LoaderArgs) {
// No deferred data for this route
return {};
}
export default function Store() {
const {route} = useLoaderData();
return (
{/* 3. Render the route's content sections */}
);
}
```
***
## Step 6: Add metaobjects to homepage
Integrate the `RouteContent` component to render metaobject sections on the homepage.
#### File: [\_index.tsx](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/templates/skeleton/app/routes/_index.tsx) ([patch](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/patches/_index.tsx.243e26.patch))
## File
```diff
@@ -1,19 +1,11 @@
-import {
- Await,
- useLoaderData,
- Link,
-} from 'react-router';
+import {useLoaderData} from 'react-router';
import type {Route} from './+types/_index';
-import {Suspense} from 'react';
-import {Image} from '@shopify/hydrogen';
-import type {
- FeaturedCollectionFragment,
- RecommendedProductsQuery,
-} from 'storefrontapi.generated';
-import {ProductItem} from '~/components/ProductItem';
+
+// @description Add metaobject content imports
+import {ROUTE_CONTENT_QUERY, RouteContent} from '~/sections/RouteContent';
export const meta: Route.MetaFunction = () => {
- return [{title: 'Hydrogen | Home'}];
+ return [{title: 'Hydrogen Metaobject | Home'}];
};
export async function loader(args: Route.LoaderArgs) {
@@ -31,14 +23,18 @@ export async function loader(args: Route.LoaderArgs) {
* needed to render the page. If it's unavailable, the whole page should 400 or 500 error.
*/
async function loadCriticalData({context}: Route.LoaderArgs) {
- const [{collections}] = await Promise.all([
- context.storefront.query(FEATURED_COLLECTION_QUERY),
+ const {storefront} = context;
+
+ // @description Query the home route metaobject
+ const [{route}] = await Promise.all([
+ storefront.query(ROUTE_CONTENT_QUERY, {
```
***
## Step 7: Display all stores
Add a store listing page that shows all stores from metaobjects with a grid layout.
#### File: [stores.\_index.tsx](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/app/routes/stores._index.tsx)
## File
```tsx
import {useLoaderData} from 'react-router';
import type {Route} from './+types/stores._index';
// 1. Add metaobject content imports
import {ROUTE_CONTENT_QUERY, RouteContent} from '~/sections/RouteContent';
export const meta: Route.MetaFunction = () => {
return [{title: 'Hydrogen | Home'}];
};
export async function loader(args: Route.LoaderArgs) {
// Start fetching non-critical data without blocking time to first byte
const deferredData = loadDeferredData(args);
// Await the critical data required to render initial state of the page
const criticalData = await loadCriticalData(args);
return {...deferredData, ...criticalData};
}
/**
* Load data necessary for rendering content above the fold. This is the critical data
* needed to render the page. If it's unavailable, the whole page should 400 or 500 error.
*/
async function loadCriticalData({context}: Route.LoaderArgs) {
const {storefront} = context;
// 2. Query for the route's content metaobject
const [{route}] = await Promise.all([
storefront.query(ROUTE_CONTENT_QUERY, {
variables: {handle: 'route-stores'},
cache: storefront.CacheNone(),
}),
// Add other queries here, so that they are loaded in parallel
]);
return {route};
}
/**
* Load data for rendering content below the fold. This data is deferred and will be
* fetched after the initial page load. If it's unavailable, the page should still 200.
* Make sure to not throw any errors here, as it will cause the page to 500.
*/
function loadDeferredData({context}: Route.LoaderArgs) {
// No deferred data for this route
return {};
}
export default function Stores() {
const {route} = useLoaderData();
return (
{/* 3. Render the route's content sections */}
);
}
```
***
## Step 8: Install rich text dependencies
Add Slate dependencies for rich text editing in metaobject sections.
#### File: [package.json](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/templates/skeleton/package.json) ([patch](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/patches/package.json.f30b0a.patch))
```diff
@@ -21,7 +21,9 @@
"react": "18.3.1",
"react-dom": "18.3.1",
"react-router": "7.9.2",
- "react-router-dom": "7.9.2"
+ "react-router-dom": "7.9.2",
+ "slate": "^0.101.4",
+ "slate-react": "^0.101.3"
},
"devDependencies": {
"@eslint/compat": "^1.2.5",
```
***
## Step 9: Create route content component
Add the main component for fetching and rendering metaobject-based route content.
#### File: [RouteContent.tsx](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/app/sections/RouteContent.tsx)
## File
```tsx
import {SECTIONS_FRAGMENT, Sections} from '~/sections/Sections';
import {EditRoute} from '~/components/EditRoute';
import type {RouteContentQuery} from 'storefrontapi.generated';
export function RouteContent({route}: {route: RouteContentQuery['route']}) {
if (!route?.sections) {
return
No route content sections
;
}
return (
{route?.id && }
{route?.sections && }
);
}
export const ROUTE_CONTENT_QUERY = `#graphql
query RouteContent($handle: String!) {
route: metaobject(handle: {type: "route", handle: $handle}) {
type
id
title: field(key: "title") {
key
value
}
sections: field(key: "sections") {
...Sections
}
}
}
${SECTIONS_FRAGMENT}
`;
```
***
## Step 10: Build featured collections section
Add a section component for displaying featured product collections from metaobjects.
#### File: [SectionFeaturedCollections.tsx](https://github.com/Shopify/hydrogen/blob/12374c8f03f82c6800000cf08e327c4db4c287bb/cookbook/recipes/metaobjects/ingredients/templates/skeleton/app/sections/SectionFeaturedCollections.tsx)
## File
```tsx
import type {
SectionFeaturedCollectionsFragment,
FeaturedCollectionImageFragment,
} from 'storefrontapi.generated';
import {parseSection} from '~/utils/parseSection';
import type {ParsedMetafields} from '@shopify/hydrogen';
import {Image} from '@shopify/hydrogen';
export function SectionFeaturedCollections(
props: SectionFeaturedCollectionsFragment,
) {
const section = parseSection<
SectionFeaturedCollectionsFragment,
{
heading?: ParsedMetafields['single_line_text_field'];
}
>(props);
const {id, heading, collections} = section;
return (
{heading &&