Complete reference for all React components in this starter, including CMS modules, page templates, and utility components.
These components map to Agility CMS modules and can be added to content zones in the CMS.
Flexible component for displaying text content alongside an image.
Location: components/agility-components/TextBlockWithImage.tsx
Fields:
interface ITextBlockWithImage {
title: string; // Main heading
content: string; // Descriptive text
tagline?: string; // Optional overline text
imagePosition: "left" | "right"; // Image placement
image: ImageField; // Image with responsive sources
primaryButton: URLField; // CTA button (optional)
highPriority?: string; // "true" for above-fold images
}Features:
- Responsive image sizing with
AgilityPic - Left or right image positioning
- Optional CTA button (internal or external links)
- Dark mode support
- Priority loading for above-the-fold images
Usage in CMS:
- Add "TextBlockWithImage" module to a content zone
- Fill in heading, content, and upload image
- Choose image position (left/right)
- Optionally add a primary button link
- Check "High Priority" for images above the fold
Code Example:
// Automatically rendered when module is added to page
<TextBlockWithImage module={module} languageCode="en-us" />Server/client split component for displaying blog posts with infinite scroll.
Location:
- Server:
components/agility-components/PostsListing/PostsListing.server.tsx - Client:
components/agility-components/PostsListing/PostsListing.client.tsx
Module Fields:
interface IPostListing {
title: string; // Listing heading
subtitle: string; // Listing subheading
preHeader: string; // Optional tagline
}Features:
- Server-side initial data fetching
- Client-side infinite scroll
- Server Actions for pagination
- Responsive grid layout
- Category badges
- Date formatting
Architecture:
PostsListing (Server Component)
├── Fetches initial posts (10 items)
├── Defines getNextPosts Server Action
└── Passes to PostsListingClient
└── Client Component
├── Manages scroll state
├── Loads more posts on scroll
└── Renders post grid
Usage in CMS:
- Add "PostListing" module to page
- Set heading and optional subheading
- Component automatically fetches and displays posts
Displays individual blog post with full content, metadata, and author info.
Location: components/agility-components/PostDetails.tsx
No Module Fields - Relies on dynamic page context
Features:
- Full post content with rich text
- Category badge and tags
- Author information
- Date formatting
- Hero image with responsive sizing
- Dark mode support
- Breadcrumb navigation
Usage:
- Automatically rendered on blog post detail pages
- Content pulled from dynamic page's
contentID - Place on "post-details" dynamic page template
Highlights a single blog post with large layout.
Location: components/agility-components/FeaturedPost.tsx
Module Fields:
interface IFeaturedPost {
post: string; // Linked content (Post dropdown)
postID: number; // Auto-populated
postTitle: string; // Auto-populated
}Features:
- Large hero image
- Post title, excerpt, and category
- Read more link
- Responsive layout
- Dark mode support
Usage in CMS:
- Add "FeaturedPost" module
- Select post from dropdown
- Component fetches and displays full post data
Simple heading component for section titles.
Location: components/agility-components/Heading.tsx
Module Fields:
interface IHeading {
title: string; // Heading text
level: "h1" | "h2" | "h3" | "h4"; // HTML heading level
alignment: "left" | "center" | "right"; // Text alignment
}Features:
- Semantic HTML headings
- Flexible alignment
- Dark mode support
- Responsive sizing
Usage in CMS:
- Add "Heading" module to zone
- Enter heading text
- Choose heading level (h1-h4)
- Set alignment preference
Renders rich HTML content from CMS.
Location: components/agility-components/RichTextArea.tsx
Module Fields:
interface IRichTextArea {
textblob: string; // HTML content
}Features:
- Tailwind Typography (
proseclass) - Dark mode prose styling
- Responsive text sizing
- Automatic HTML sanitization (via
html-react-parser)
Usage in CMS:
- Add "RichTextArea" module
- Use rich text editor to create content
- Supports headings, lists, links, bold, italic, etc.
Styling: Uses Tailwind Typography plugin for beautiful typographic defaults:
<div className="prose dark:prose-invert max-w-none">
{parse(fields.textblob)}
</div>Fallback component when module isn't registered.
Location: components/agility-components/NoComponentFound.tsx
Features:
- Displays error message with module name
- Helpful for debugging missing components
- Prevents page crashes
When shown:
- Module exists in CMS but not registered in React
- Typo in module name registration
- Module file not imported
How to fix:
- Create the component file
- Register in
components/agility-components/index.ts - Ensure name matches exactly
Page templates define the layout structure for pages in Agility CMS.
Default page template with a main content zone.
Location: components/agility-pages/MainTemplate.tsx
Structure:
<div className="main-template">
<ContentZone
name="MainContent"
page={page}
getModule={getModule}
/>
</div>Content Zones:
- MainContent - Primary content area
Usage:
- Most pages use this template
- Modules added to "MainContent" zone render sequentially
- Set as page template when creating pages in CMS
Shared components used throughout the site.
Main navigation header with dark mode toggle.
Location: components/common/SiteHeader.tsx
Features:
- Responsive navigation (desktop/mobile)
- Dark mode toggle switch
- Logo with link to homepage
- Mobile menu drawer
- Auto-detects system color scheme preference
- Navigation items from sitemap
Props:
interface Props {
header: IHeaderData | null;
}
interface IHeaderData {
logo: ImageField;
siteName: string;
links: Array<{
title: string;
path: string;
}>;
}Dark Mode:
- Uses Headless UI
<Switch>component - Persists to
<html class="dark">for Tailwind - Listens to system preference changes
- Icons:
IconBrightnessDown(light) andIconBrightnessUp(dark)
Usage:
// In app/layout.tsx
const header = await getHeaderContent();
<SiteHeader header={header} />Footer with social links and copyright.
Location: components/common/SiteFooter.tsx
Features:
- Social media links (Twitter, LinkedIn, GitHub, etc.)
- Footer navigation links
- Copyright notice
- Logo display
- Dark mode support
Props:
interface Props {
footer: IFooterData | null;
}
interface IFooterData {
logo: ImageField;
copyright: string;
links: Array<{
title: string;
path: string;
}>;
socialLinks: Array<{
platform: string;
url: string;
icon: string;
}>;
}Usage:
// In app/layout.tsx
const footer = await getFooterContent();
<SiteFooter footer={footer} />Visual indicator for preview/live mode.
Location: components/common/PreviewBar.tsx
Features:
- Shows current mode (Preview/Live/Dev)
- Exit preview button
- Only visible in preview or development mode
- Sticky positioning
- Link to GitHub repo
Modes:
- Preview Mode - Shows "Preview" badge with exit button
- Live Mode (Dev) - Shows "Live" badge (development only)
- Production - Hidden
Usage:
// In app/layout.tsx
<PreviewBar />Error message display component.
Location: components/common/InlineError.tsx
Props:
interface Props {
message: string;
}Features:
- Centered error message
- Consistent styling
- Dark mode support
- Used for missing content or API errors
Usage:
if (!post) {
return <InlineError message="Post not found" />;
}touch components/agility-components/MyNewComponent.tsx// components/agility-components/MyNewComponent.tsx
import { UnloadedModuleProps } from "@agility/nextjs";
import { getContentItem } from "@/lib/cms/getContentItem";
interface IMyNewComponent {
heading: string;
description: string;
showButton: boolean;
}
export default async function MyNewComponent({
module,
languageCode,
}: UnloadedModuleProps) {
const { fields } = await getContentItem<IMyNewComponent>({
contentID: module.contentid,
languageCode,
});
return (
<section className="py-12 px-8">
<div className="max-w-7xl mx-auto">
<h2 className="text-3xl font-bold">{fields.heading}</h2>
<p className="mt-4">{fields.description}</p>
{fields.showButton && (
<button className="mt-6 px-6 py-3 bg-blue-600 text-white rounded">
Learn More
</button>
)}
</div>
</section>
);
}// components/agility-components/index.ts
import MyNewComponent from "./MyNewComponent";
const allModules = [
// ... existing modules
{ name: "MyNewComponent", module: MyNewComponent },
];- Go to Settings > Models > Modules
- Click "+ New Module"
- Name: "MyNewComponent" (must match registration name)
- Add fields:
heading(Text)description(Long Text)showButton(Boolean)
- Save module
- Edit a page in Agility CMS
- Click "+ Add Module" in a content zone
- Select "MyNewComponent"
- Fill in fields
- Save and publish
// Async component that fetches data
export default async function MyComponent({ module, languageCode }) {
const data = await getContentItem({ ... });
return <div>{data.title}</div>;
}When to use:
- Default for all components
- Fetch data directly
- No user interaction
- SEO-friendly content
"use client";
import { useState } from "react";
export default function MyInteractiveComponent({ initialData }) {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}When to use:
- User interactions (clicks, form input)
- React hooks (useState, useEffect, etc.)
- Browser APIs (localStorage, etc.)
// Server Component (parent)
export default async function Parent({ module }) {
const data = await fetchData();
// Pass data to Client Component
return <ClientChild data={data} />;
}Benefits:
- Fetch on server (fast, SEO-friendly)
- Interactivity on client (when needed)
- Best of both worlds
- Create interface for module fields:
interface IMyModule {
title: string;
image?: ImageField; // Optional field
items: Array<string>;
}- Use generics for content fetching:
const data = await getContentItem<IMyModule>({
contentID: module.contentid,
languageCode,
});- Export interface for reuse:
// lib/types/IMyModule.ts
export interface IMyModule {
// ...
}- Use Tailwind CSS classes:
<div className="max-w-7xl mx-auto py-12 px-4">- Support dark mode:
<div className="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">- Responsive design:
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3">- Use semantic HTML:
<article>
<header>
<h1>...</h1>
</header>
<main>...</main>
</article>-
Preview Mode:
- Make changes in Agility CMS
- Click "Preview" button
- Verify component renders correctly
- Test all field variations
-
Dark Mode:
- Toggle dark mode switch
- Verify colors and contrast
- Check all component states
-
Responsive:
- Test on mobile, tablet, desktop
- Use browser DevTools responsive mode
- Verify layout doesn't break
Component not rendering:
- Check component is registered in
index.ts - Verify module name matches exactly (case-sensitive)
- Look for errors in browser console
- Check Network tab for API calls
Data not showing:
- Verify field names match CMS model
- Check TypeScript interface matches CMS fields
- Add
console.log(fields)to inspect data - Ensure content is published in CMS
For more complex component examples, see the nextjs-demo-site-2025 repository:
- Carousel - Multi-slide carousel with navigation
- Testimonials - Customer testimonial grid
- Pricing Cards - Pricing tiers with features
- FAQ Accordion - Expandable question/answer list
- Contact Form - Form submission with validation
- Personalized Components - Audience-based content
- A/B Testing - Variant testing components
- AI-Powered Search - Intelligent search interface
This component library provides a solid foundation for building content-rich websites. Mix and match components, customize styling, and create your own to build unique experiences.