Skip to content

React / Next.js

ACMS works seamlessly with React and Next.js applications. This guide covers setup, usage patterns, and reactive updates.

Terminal window
npm install @useacms/client @useacms/cli

Import the acms object and use it directly in your components:

import { acms } from '@useacms/client';
export default function Hero() {
return (
<section className="hero">
<h1>{acms.hero.title}</h1>
<p>{acms.hero.subtitle}</p>
<a href={acms.hero.ctaLink}>{acms.hero.ctaText}</a>
</section>
);
}

Fields are automatically registered the first time they are accessed during development.

For real-time content updates without page reloads, create a custom hook using the subscribe function:

hooks/use-acms.ts
import { useState, useEffect } from 'react';
import { acms, subscribe } from '@useacms/client';
export function useAcms() {
const [, forceUpdate] = useState(0);
useEffect(() => {
const unsubscribe = subscribe(() => {
forceUpdate((n) => n + 1);
});
return unsubscribe;
}, []);
return acms;
}

Then use it in your components:

import { useAcms } from '@/hooks/use-acms';
export default function Hero() {
const content = useAcms();
return (
<section>
<h1>{content.hero.title}</h1>
<p>{content.hero.subtitle}</p>
</section>
);
}

Now when content changes (via the dashboard, API, or direct edits), the component re-renders automatically.

ACMS works with both Server Components and Client Components in Next.js App Router.

Use acms directly in Server Components for build-time content:

app/page.tsx
import { acms } from '@useacms/client';
export default function HomePage() {
return (
<main>
<h1>{acms.hero.title}</h1>
<p>{acms.hero.subtitle}</p>
</main>
);
}

For reactive updates, use the useAcms hook in Client Components:

'use client';
import { useAcms } from '@/hooks/use-acms';
export default function LiveHero() {
const content = useAcms();
return (
<section>
<h1>{content.hero.title}</h1>
<p>{content.hero.subtitle}</p>
</section>
);
}

Works the same way in the Pages Router:

pages/index.tsx
import { acms } from '@useacms/client';
export default function Home() {
return (
<div>
<h1>{acms.home.title}</h1>
<p>{acms.home.description}</p>
</div>
);
}

Create acms.config.ts in your project root:

import { defineConfig } from '@useacms/client';
import { localFile, githubGist } from '@useacms/cli/adapters';
export default defineConfig({
dev: localFile({ path: './acms.json' }),
production: githubGist({
token: process.env.GITHUB_TOKEN,
gistId: process.env.GIST_ID,
}),
strategy: 'build-time',
});

Add scripts to your package.json:

{
"scripts": {
"dev": "concurrently \"acms dev\" \"next dev\"",
"build": "next build",
"start": "next start"
}
}

Or use separate terminals:

Terminal window
# Terminal 1
acms dev
# Terminal 2
next dev

Render array fields using .map():

import { acms } from '@useacms/client';
export default function FeatureList() {
return (
<ul>
{acms.features.map((feature, index) => (
<li key={index}>{feature}</li>
))}
</ul>
);
}

Use image fields in <img> or Next.js <Image>:

import Image from 'next/image';
import { acms } from '@useacms/client';
export default function Logo() {
return (
<Image
src={acms.brand.logo}
alt={acms.brand.name}
width={200}
height={50}
/>
);
}

Use boolean fields for conditional rendering:

import { acms } from '@useacms/client';
export default function Banner() {
if (!acms.banner.visible) return null;
return (
<div className="banner">
<p>{acms.banner.message}</p>
</div>
);
}