This repository contains XM Cloud Front End Application Starter Kits - multiple Next.js starter applications and SPA examples for Sitecore XM Cloud development. Each starter demonstrates modern headless CMS patterns with Sitecore XM Cloud integration.
/examples/- Contains starter front-end applications (Next.js and SPA)/authoring/- Sitecore content items, templates, and deployment configurations/local-containers/- Docker setup for local development environmentsxmcloud.build.json- Primary configuration for XM Cloud deployment
- basic-nextjs - Simple Next.js starter with basic XM Cloud integration
- kit-nextjs-article-starter - Solterra & Co. - Editorial-style template for lifestyle brands
- kit-nextjs-location-finder - Alaris - Car brand template with location finder functionality
- kit-nextjs-product-listing - SYNC - Product-focused template for audio gear companies
- kit-nextjs-skate-park - Simple demo site showcasing component examples
- basic-spa - SPA starter kit with Angular and Node proxy
- Tailwind-based styling with Shadcn/ui components
- Personalized homepage via URL parameters
- Modular component architecture with variants
- Localization support for English (en) and Canadian English (en-CA)
- Next.js 14+ - React framework with App Router and Pages Router support
- TypeScript - Strict type safety throughout all components
- Sitecore XM Cloud - Headless content management and delivery
- Sitecore Content SDK - Modern SDK for XM Cloud integration (
@sitecore-content-sdk/nextjs) - Tailwind CSS - Utility-first CSS with container queries (@container)
- Shadcn/ui - Modern component library with accessibility features
- Framer Motion - Animation library for interactive components
- Lucide React - Icon library for consistent iconography
- next-localization - Internationalization with dictionary support
- change-case - String case transformation utilities
- React Hook Form - Form handling with validation
- Zod - TypeScript-first schema validation
- Docker - Containerized local development with Sitecore CM
- Node.js LTS - JavaScript runtime environment
- npm - Package management across all starter applications
- Component directories contain main file, variants, and props
- Main component file should contain variants and props following the Locality of Behavior pattern
- Using
.dev.tsxfiles for variant implementations is discouraged unless maintainability becomes difficult for the component and separation cannot be avoided - Shared utilities in dedicated directories
- Group UI components in
ui/subdirectory
- Enable strict mode in all projects
- Prefer explicit types over
any - Use discriminated unions for complex state
- Export types at module boundaries for reusability
- Define proper interfaces for XM Cloud data structures
- Prefer pure functions where possible
- Use immutable data patterns
- Avoid side effects in business logic
- Compose small, focused functions
- Use React hooks appropriately
Follow the Locality of Behavior pattern:
// ComponentName.tsx - Main component file with all variants
import type React from 'react';
import { useSitecore } from '@sitecore-content-sdk/nextjs';
import { ComponentProps } from '@/lib/component-props';
import { Field, ImageField } from '@sitecore-content-sdk/nextjs';
interface ComponentParams {
[key: string]: any;
}
interface ComponentFields {
title?: { jsonValue: Field<string> };
subtitle?: { jsonValue: Field<string> };
backgroundImage?: { jsonValue: ImageField };
}
interface ComponentProps extends ComponentProps {
params: ComponentParams;
fields: {
data: {
datasource: ComponentFields;
};
};
isPageEditing?: boolean;
}
// Export named variants
export const Default: React.FC<ComponentProps> = (props) => {
const { page } = useSitecore();
const { isEditing } = page.mode;
return <ComponentDefault {...props} isPageEditing={isEditing} />;
};
export const ThreeUp: React.FC<ComponentProps> = (props) => {
const { page } = useSitecore();
const { isEditing } = page.mode;
return <ComponentThreeUp {...props} isPageEditing={isEditing} />;
};Always validate datasource existence:
- Always check
fields?.data?.datasourceexistence - Use
NoDataFallbackcomponent for missing datasources - Handle both editing and preview modes
- Provide meaningful error messages
import { NoDataFallback } from '@/utils/NoDataFallback';
export const ComponentDefault: React.FC<ComponentProps> = (props) => {
const { fields, isPageEditing } = props;
if (!fields?.data?.datasource) {
return <NoDataFallback componentName="ComponentName" />;
}
const { title, description, image } = fields.data.datasource;
// Safe field access with optional chaining
return (
<section>
{title?.jsonValue && (
<Text field={title.jsonValue} tag="h1" />
)}
</section>
);
};Handle destructuring errors gracefully:
// ✅ Safe destructuring with fallbacks
const { titleRequired, descriptionOptional } = fields || {};
// ✅ Safe nested destructuring
const { data: { datasource } = {} } = fields || {};
// ✅ Safe field access with optional chaining
field={fields.data?.datasource?.title?.jsonValue}
// ❌ Unsafe - can throw destructuring errors
const { title } = fields.data.datasource; // Error if fields.data is nullSitecore Field Components:
- Use
@sitecore-content-sdk/nextjsfield components - Access field values through
jsonValueproperty - Handle optional fields with conditional rendering
- Use proper semantic HTML tags
import { Text, RichText, Image } from '@sitecore-content-sdk/nextjs';
// Field rendering patterns
{title?.jsonValue && (
<Text
tag="h1"
field={title.jsonValue}
className="hero-title text-4xl font-bold"
/>
)}
{description?.jsonValue && (
<RichText field={description.jsonValue} />
)}
{image?.jsonValue && (
<Image
field={image.jsonValue}
alt={title?.jsonValue?.value || 'Hero image'}
className="w-full h-auto"
/>
)}Page Editing Support:
- Use
useSitecorehook to access page mode - Check
page.mode.isEditingfor editing state - Pass
isPageEditingprop to variant components - Provide different rendering for editing vs. preview
import { useSitecore } from '@sitecore-content-sdk/nextjs';
export const Default: React.FC<ComponentProps> = (props) => {
const { page } = useSitecore();
const { isEditing } = page.mode;
const isEditMode = props.isPageEditing || isEditing;
if (isEditMode) {
// Simplified rendering for editing mode
}
// Normal rendering
};SDK Submodule Usage:
- Main package: Use for components and client-side functionality
- Submodules: Only use appropriate submodules for specific contexts
- Server-only: Never import
/config-clior/toolsin client components
// ✅ SAFE - Client-side component usage
import {
Text,
RichText,
Image,
Link,
Field,
LinkField,
ImageField,
useSitecore,
SitecoreProvider,
Placeholder
} from '@sitecore-content-sdk/nextjs';
// ✅ SAFE - Middleware usage (edge runtime)
import {
LocalizationMiddleware,
RedirectsMiddleware
} from '@sitecore-content-sdk/nextjs/middleware';// ❌ NEVER in client components
// ✅ ONLY in server-side contexts (sitecore.config.ts, sitecore.cli.config.ts)
import { defineConfig } from '@sitecore-content-sdk/nextjs/config';
import { defineCliConfig } from '@sitecore-content-sdk/nextjs/config-cli';
import { generateSites, generateMetadata, extractFiles } from '@sitecore-content-sdk/nextjs/tools';
// ✅ ONLY in lib/sitecore-client.ts or server utilities
import { SitecoreClient, GraphQLRequestClient } from '@sitecore-content-sdk/nextjs/client';import { cn } from '@/lib/utils';
import { Button } from '@/components/ui/button';
<div className={cn(
'@container bg-primary rounded-default',
'relative mx-auto my-6 max-w-7xl px-4 py-16',
isActive && '@md:w-full'
)}>- Use container queries (@container) for component-based responsive design
- Implement mobile-first approach with Tailwind breakpoints
- Use Shadcn/ui components for consistent accessibility
- Component directories: kebab-case (
article-header/,product-listing/) - Component files with all variants as well as the props: PascalCase (
Hero.tsx,ProductListing.tsx) - Utility files: camelCase (
dateUtils.ts,componentProps.ts)
- Variables: camelCase (
isActive,prefersReducedMotion) - Boolean variables: prefix with
is,has,can,should - Event handlers: prefix with
handle(handleClick,handleKeyDown) - Constants: UPPER_SNAKE_CASE (
DEFAULT_TIMEOUT,USER_ZIPCODE)
- Start with the main component file (
ComponentName.tsx) - Define TypeScript interfaces for params, fields, and props
- Create variant dispatchers that use
useSitecorehook - Implement variant components with proper validation
- Add styling with Tailwind CSS and Shadcn/ui
- Test with and without datasources in editing mode
- Use
'use client'directive for client-side interactivity - Implement proper ARIA attributes for interactive components
- Use React hooks like
useState,useEffect,useRefappropriately - Check for
prefers-reduced-motionwhen using animations
'use client';
import { useState, useEffect } from 'react';
export const InteractiveComponent: React.FC<Props> = (props) => {
const [prefersReducedMotion, setPrefersReducedMotion] = useState(false);
useEffect(() => {
const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
setPrefersReducedMotion(mediaQuery.matches);
}, []);
// Component implementation with motion respect
};- Use Next.js
MetadataAPI for proper SEO - Implement structured data for rich snippets
- Use semantic HTML elements for better accessibility
# Navigate to any starter
cd examples/kit-nextjs-article-starter
# Copy environment template
cp .env.remote.example .env.local
# Edit .env.local with your XM Cloud values
# Install dependencies and start
npm install
npm run devSITECORE_EDGE_CONTEXT_ID=your-context-id
NEXT_PUBLIC_DEFAULT_SITE_NAME=your-site-name
NEXT_PUBLIC_SITECORE_EDGE_CONTEXT_ID=your-public-context-id
SITECORE_EDITING_SECRET=your-editing-secretnode_modules/- Installed packages.next/,dist/,out/,build/- Build outputspackage-lock.json,yarn.lock- Lock files.env.local,.env.*.local- Local environment files*.itempackage,*.sicpackage- Sitecore packages.sitecore/user.json- User-specific configs
.ts,.tsx,.js,.jsxfiles insrc/next.config.js,tsconfig.json,package.json.css,.scssfiles.sitecore/component-map.ts