Template Sections

Update the UIs of existing sections while keeping the ecommerce boilerplate composable and data-aware.

What is a section?

A section is a reusable slice of a page. Each section:

  • Receives a Section object with a type string and a config payload from JSON or CMS.
  • Renders independently (server or client) and can fetch its own data.
  • Is mapped to section.type in both JSON mocks and CMS responses.

Files live in app/_components/sections/ (e.g., HeroSection.tsx, ProductsSection.tsx, BannerSection.tsx, etc.).

Scope: You cannot add new sections or modify core plumbing. Changes must stay within existing section UIs (styling, layout, copy handling, states).


Anatomy of a section

  • Signature: Every section component accepts { section: Section }.
  • Config-driven props: All styling/content comes from section.config (titles, images, limits, filters, CTAs). Avoid hardcoded copy.
  • Data awareness: Sections can call hooks/fetchers for live data (e.g., useProductsQuery in ProductsSection, getFileUrl for assets). Provide graceful fallbacks for empty/error states.
  • Client vs server: Add "use client" only when needed (hooks, state, effects). Many presentational sections can stay server components.

Example: HeroSection.tsx reads section.config.image, title, description, and primaryCta and uses helpers like getFileUrl/templateUrl to resolve assets and links.


Where sections are registered

  • Build/local rendering: app/page.tsx builds a SectionComponentMap and calls renderSections with pageItems from data/pages/index.json.
  • CMS-driven rendering: lib/usePage.tsx switches on section.type when rendering pages like about/page.tsx and contact/page.tsx.

For a section to render in all contexts, it must be added to both maps.


Updating an existing section (UI-only checklist)

  1. Stay within the file: Edit the section component in app/_components/sections/*.tsx. Do not add new section files or modify registries.
  2. Keep the contract: Do not change section.type or how section.config is read; only adjust rendering (markup, classes, layout).
  3. Respect data hooks: If the section fetches data (e.g., ProductsSection uses useProductsQuery), leave data flow intact and only update presentation or states.
  4. Handle states: Preserve/clarify loading, empty, and error handling. If adding UI polish, ensure these states still work.
  5. Test locally: Use existing mocks in data/pages/*.json or CMS data with BUILD_MODE=true to verify UI changes.

Common patterns from existing sections

  • Media-heavy: BannerSection and HeroSection resolve images with getFileUrl and provide clickable CTAs via templateUrl.
  • List/data-driven: ProductsSection, ProductCategoriesSection, ToursSection, CmsPostsSection, and GallerySection fetch or render collections, handle loading placeholders, empty states, and errors.
  • Form/contact: ContactSection and FormSection read fields from config and use shared UI components.
  • Personalization: LastViewedProductsSection reads from cart/context to personalize content.

Use these as references for states, fallbacks, and config shapes.


Data contracts

  • Section type (see types/sections.ts):
    • type: string
    • config?: any (shape is section-specific; document the keys you expect)
    • Optional metadata: content, contentType, contentTypeId, order, name
  • Page JSON (data/pages/*.json) uses pageItems: Section[]. CMS responses mirror this shape (section.type, section.config).

Document expected config fields in PRs or code comments near the section to keep designers and CMS authors aligned.


Testing a section

  • Local mock: Add the section to a data/pages/*.json page and run yarn dev with BUILD_MODE unset. Verify rendering, responsiveness, and accessibility.
  • Builder/CMS: Set BUILD_MODE=true and load the page via the builder to ensure the section works with live data and params.
  • Quality checks: Run yarn lint and ensure the section handles loading, empty, and error states without crashing.