DEMO

Code

Integrating AEM Universal Editor with a Next.js App

The AEM Universal Editor lets authors edit content directly inside your existing Next.js experience while still treating AEM as a headless CMS. This guide walks through the core integration steps, assuming:

For background on concepts and capabilities, see the Universal Editor introduction and headless use cases in AEM documentation.Universal Editor Introduction · Universal Editor Use Cases and Learning Paths

1. Connect Next.js to AEM Headless (Content Fragments + GraphQL)

First make sure your Next.js app is already consuming AEM headless content:

  1. Model your content in AEM as Content Fragments and publish your GraphQL endpoint.
  2. From Next.js, call the GraphQL endpoint (SSR, ISR, or client‑side – any is fine):
// Example: basic GraphQL fetch in Next.js
async function fetchArticles() {
  const res = await fetch(
    'https://publish-pXXXX-eYYYY.adobeaemcloud.com/graphql/execute.json/my-endpoint',
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ query: '{ articleList { items { _path title body } } }' }),
    }
  );
  return res.json();
}

If you’re not at this stage yet, walk through the AEM Headless tutorials first; they use a React app but the pattern is identical for Next.js.Edit the React app with Universal Editor · React app editing using Universal Editor

2. Bootstrap Universal Editor in your Next.js <head>

Next, you need to tell the Universal Editor how to connect your page to AEM.

In your root layout (e.g., _document.tsx or app/layout.tsx), add the AEM connection meta tag and Universal Editor CORS script to the <head>:

// Example for Next.js _document.tsx
import Document, { Html, Head, Main, NextScript } from 'next/document';

class MyDocument extends Document {
  render() {
    const aemAuthorHost = 'https://author-pXXXX-eYYYY.adobeaemcloud.com';

    return (
      <Html>
        <Head>
          {/* Universal Editor connection to AEM Author */}
          <meta
            name="urn:adobe:aue:system:aemconnection"
            content={`aem:${aemAuthorHost}`}
          />
          {/* Universal Editor CORS helper */}
          <script
            src="https://universal-editor-service.adobe.io/cors.js"
            async
          />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

export default MyDocument;

Key points:

3. Mark editable regions with data-aue-* attributes

The Universal Editor inspects your rendered HTML and uses data-aue-* attributes to know:

A simple example for text stored in a Content Fragment field:

// inside a Next.js component rendering an article teaser
export function ArticleTeaser({ fragmentPath, title }) {
  return (
    <h2
      data-aue-resource={`urn:aemconnection:${fragmentPath}`}
      data-aue-type="content-fragment"
      data-aue-field="title"
    >
      {title}
    </h2>
  );
}

Where:

For lists of CFs rendered via GraphQL, you typically:

  1. Return fragment paths in your query.
  2. For each rendered item, add data-aue-resource and data-aue-field so the editor can jump from DOM → CF field.

The React tutorial shows more variations of these attributes; the same patterns apply to Next.js.Edit the React app with Universal Editor

4. Wire preview vs live correctly (AEM + Next.js)

You’ll usually have two frontends:

For example:

# Preview deployment (Cloudflare env)
NEXT_PUBLIC_AEM_GRAPHQL=https://preview-pXXXX-eYYYY.adobeaemcloud.com/graphql/execute.json/my-endpoint

# Production deployment
NEXT_PUBLIC_AEM_GRAPHQL=https://publish-pXXXX-eYYYY.adobeaemcloud.com/graphql/execute.json/my-endpoint

Then:

Universal Editor itself always connects to Author; your Next.js app decides whether it reads Preview or Publish when running outside UE.

5. Open your Next.js app in Universal Editor

Once headless integration and instrumentation are in place:

  1. Deploy your Next.js app to a URL UE can reach (dev/stage/preview).

  2. In AEM, open the Universal Editor (via Sites console or direct URL).

  3. Provide the public URL of your Next.js page as the “canvas” URL.

  4. The Universal Editor will:

    • Load your Next.js page
    • Inspect the data-aue-* attributes
    • Resolve them back to AEM Content Fragments via urn:aemconnection:…
    • Let authors edit fields inline or via the properties rail, and save back to AEM

From the author’s perspective, they’re just editing the live Next.js UI; behind the scenes, the editor maps changes back to Content Fragments.Universal Editor Introduction

6. Where to go deeper

Once the main flow is working, typical next steps are:

For more detailed examples (including full sample apps), the React + Universal Editor tutorial is the best reference; translate its React patterns directly into your Next.js components and layouts.React app editing using Universal Editor

References