Leitfaden zur Block-Entwicklung

Baue eigene Blöcke für deine Headless-Cmssy-Site - defineBlock, fields, die Block-Komponente und context.

29. Juni 2026

Block-Anatomie

Ein Cmssy-Block lebt in deinem eigenen Next.js-Repo als Ordner unter blocks/:

  • block.ts — deklariert den Block mit defineBlock + fields (Typ, Label und editierbares Schema)
  • Hero.tsx — die React-Komponente, die den Inhalt rendert

Registriere den Block in cmssy/blocks.ts. Der Editor liest das Schema jedes Blocks über die SDK-Bridge — fügst du einen Block zu einer Seite hinzu, wird aus deinen fields ein Editor-Formular gerendert.


Einen Block definieren

// blocks/hero/block.ts
import { defineBlock, fields } from "@cmssy/react";
import Hero from "./Hero";

// Separat exportiert, damit die Komponente ihre Props daraus ableiten kann.
export const heroProps = {
  heading: fields.text({ label: "Heading", defaultValue: "Welcome" }),
  body: fields.richText({ label: "Body" }),
  ctaUrl: fields.link({ label: "CTA URL", defaultValue: "/signup" }),
  showCta: fields.boolean({ label: "Show CTA", defaultValue: true }),
};

export const heroBlock = defineBlock({
  type: "hero",
  label: "Hero",
  component: Hero,
  props: heroProps,
});

Feldtypen: text, textarea, richText, markdown, number, date, datetime, boolean, color, media, link, url, email, select, radio, multiselect, relation, repeater, table, json, form, pageSelector. Siehe Schema & Feldtypen.


Die Block-Komponente

Blöcke erhalten { content, context, data }. Der Inhalt ist bereits für die aktive Locale aufgelöst, du kannst Felder also direkt lesen.

// blocks/hero/Hero.tsx
import type { BlockProps } from "@cmssy/react";
import { heroProps } from "./block";

export default function Hero({ content, context }: BlockProps<typeof heroProps>) {
  // Aus dem Schema typisiert: heading ist ein string, showCta ein boolean.
  const { heading, showCta, ctaUrl } = content;
  const isPreview = context?.isPreview ?? false;

  return (
    <section>
      <h1>{heading}</h1>
      {showCta && <a href={ctaUrl}>Get started</a>}
    </section>
  );
}

Mit BlockProps<typeof heroProps> ist das Schema die einzige Stelle, an der ein Feld benannt wird. Benenne heading um, und die Komponente kompiliert nicht mehr - statt still nichts zu rendern, was das Lesen von content.heading auf einem Record<string, unknown> getan hätte. Hat der Block einen loader, gib dessen Rückgabetyp als zweites Argument mit: BlockProps<typeof heroProps, Posts> typisiert auch die data-Prop.

context trägt locale ({ current, default, enabled }) und isPreview (true im Editor), dazu forms für jedes vom Block referenzierte Formular. auth und workspace sind da, wenn deine App sie über buildBlockContext liefert. Locale-abhängige UI liest context.locale.enabled. Eigene Modelle oder Records lädst du mit createCmssyClient; für SSR füge einen loader hinzu und lies sein Ergebnis aus data. Siehe Erweiterte Funktionen und Server-Loader.


Registrieren & ausliefern

// cmssy/blocks.ts
import { heroBlock } from "@/blocks/hero/block";
export const blocks = [heroBlock];

Führe pnpm dev aus, öffne den Seiten-Editor, und dein Block erscheint im Picker. Deploye deine Next.js-App zum Ausliefern — es gibt keinen separaten Block-Build- oder Publish-Schritt.


Nächste Schritte

Fang an, Blöcke zu bauen

Richte das SDK ein, dann erstelle und registriere deinen ersten Block.