Nexus CMS

Comment directives

Control the compiler with simple top-of-file comments.

Names are auto-derived from your component/function names. When you need to override the defaults, add a comment directive near the top of the file.

@cms-ignore

Skip a whole file/page — no regions are created for it.

// @cms-ignore
export default function Dashboard() { /* ... */ }

@cms-readonly

Regions are still discovered (and visible in the editor) but can never be edited.

// @cms-readonly
export function LegalCopy() {
  return <p>© 2026 Acme, Inc. All rights reserved.</p>;
}

@cms-name(...)

Override the auto-derived display name for the page/file.

// @cms-name(Marketing Home)
export default function Page() { /* ... */ }

@cms-locales(...)

Restrict the locale set for a file.

// @cms-locales(en,ar)
export function Hero() { /* ... */ }

@cms-layout(...) (element — collections)

Place above a .map(...) to tell the runtime how to clone new items so bento / alternating grids keep matching spans:

{/* @cms-layout(bento) */}
{FEATURES.map((f) => (
  <Reveal key={f.title} className={f.span}>…</Reveal>
))}

Values: bento · alternating · stack · grid.
bento / alternating cycle sibling templates (including md:col-span-* classes) when you Add an item. Without the directive, arrays named like FEATURES also auto-hint bento.

@cms-richtext / @cms-unite (element)

Place a JSX comment immediately above an element to treat it as one editable text field. Use this when a sentence is split across multiple nodes only for decoration (highlight, underline, motion wrappers, etc.).

export function Hero() {
  return (
    <>
      {/* @cms-richtext */}
      <p>
        {start}
        <Highlighter>{phrase}</Highlighter>
        {end}
      </p>
    </>
  );
}

The compiler also auto-detects this pattern for known decorative wrappers (Highlighter, RoughNotation, motion.span, name matches like *Highlight*, …): headings and paragraphs that only contain text + those wrappers become a single region without a directive. Native formatting (<strong>, <em>, …) still becomes a richtext region as before.

@cms-unite is an alias of @cms-richtext.

@cms-section (element)

Native <section> and <article> elements are automatically discovered as section regions — hideable page blocks in the editor (Hero, Features, CTA, …). Use @cms-section when a page block uses a plain <div> (or similar) as its root:

export function Promo() {
  return (
    <>
      {/* @cms-section @cms-name(Promo band) */}
      <div className="promo">
        <h2>Ship faster</h2>
      </div>
    </>
  );
}

Sections are visibility-only (no value editor). Nested text/image/link fields remain editable when the section is shown.

Authoring mindset

Nexus is not pure drag-and-drop. The compiler discovers editable regions from your JSX; you still tell it what is marketing copy vs chrome:

  • Decorative previews, hover followers, carousel chrome → @cms-ignore
  • Prices/features from an API or product config → @cms-readonly or ignore
  • Sentences split only for highlights/motion → @cms-richtext (or auto-unite)
  • Non-<section> page blocks you want to hide → @cms-section

Run nexus doctor for reminders and a best-effort scan of motion-heavy files missing @cms-ignore.

Edit mode and custom interactions

Comment directives control discovery (what becomes a CMS field). They cannot cancel React hover handlers (tilt, glimpse previews, custom cursors).

In edit mode Nexus freezes CSS/WAAPI/GSAP and hides [data-nexus-pointer-overlay]. For custom wrappers that still misbehave, use the package helpers:

import { useNexusEditMode } from "@nexus-cms/react";

export function LinkGlimpse({ children, ...props }) {
  const editing = useNexusEditMode();
  if (editing) return <a {...props}>{children}</a>;
  return <FancyHoverPreview {...props}>{children}</FancyHoverPreview>;
}

Also available: isNexusEditMode(), subscribeNexusEditMode(), and the nexus:edit-freeze window event (detail.phase: "settle" | "release").

Mark decorative follower layers with data-nexus-pointer-overlay so freeze CSS hides them automatically.

Handling UI changes

When the UI changes, re-run nexus generate (or keep nexus watch running). Use nexus check to see drift:

npx nexus check --ci

It reports new regions to wire up, removed regions whose overrides are now orphaned, and changed regions — perfect for a CI gate.

On this page