Rendering variants

A rendering variant is one of several visual layouts for the same Sitecore-aware component — the same props shape, a different composition. Sitecore picks which variant to render per placement, so authors can drop a single component on a page and get a different layout depending on context.

Before you reach for a variant, ask whether the change is actually a parameter:

  • It's a variant when the fields, composition, or role of the component differ — different regions, different placeholders, a different shape of data on the page.
  • It's a parameter when the shape stays the same and only orthogonal style or behaviour changes — a colour scheme, a size, a boolean toggle.

Parameters are props. Variants are separate exports.

Each variant is its own named export. They all accept the same props type — typically the component's shared …Props alias.

// components/ui/card-block.tsx — two variants, one props shape
import type { CardBlockProps } from "./card-block.types";

/** Default — source-driven body + footer + actions. */
export function CardBlock(props: CardBlockProps) {
  return (/* … */);
}

export const Default = CardBlock;

/** Placeholders — source-driven head, body and footer come from
 *  Sitecore placeholders. */
export function Placeholders(props: CardBlockProps) {
  return (/* … */);
}

One of the exports is conventionally aliased as Default— that's what Sitecore falls back to when no other variant is named.

A variantprop looks tidy but it collapses the component's public surface into one function. Sitecore's rendering picker can't target it; the bundle inlines every branch even when only one is in use; and a missing variant fails silently inside the function instead of loudly at import.

// DON'T do this — a discriminator prop is not a rendering variant.
type CardBlockProps = {
  variant: "default" | "placeholders";
  // …
};

export function CardBlock({ variant, ...rest }: CardBlockProps) {
  if (variant === "placeholders") {
    return <PlaceholdersImpl {...rest} />;
  }
  return <DefaultImpl {...rest} />;
}

Keep them separate.

To preview a component in the showcase, register a renderer in _renderer-manifest.ts. The manifest maps a renderer name (a string referenced by variant.json) to a React component and its Zod schema.

// src/app/(registry)/showcase/preview/[name]/renderers/_renderer-manifest.ts
import {
  CARD_BLOCK_PREVIEW_SCHEMA,
  CardBlockPreview,
} from "./card-block-preview";

export const RENDERER_MANIFEST = {
  // …
  CardBlockPreview: {
    Component: CardBlockPreview,
    schema: CARD_BLOCK_PREVIEW_SCHEMA,
  },
  // …
} as unknown as Record<string, RendererManifestEntry>;

The schema is used to generate the Content tab's form controls and to validate variant JSON at build time.

Variant content lives next to the component name under src/app/(registry)/showcase/preview/[name]/content/. A single variant uses variant.json; multiple variants use variants.json (plural) with a list of named entries.

Single variant

// content/blocks/facet-list/variant.json — a single variant
{
  "id": "variant",
  "label": "Variant",
  "component": "FacetListPreview",
  "props": {
    "variant": "variant"
  }
}

Multiple variants

// content/primitives/icon/variants.json — multiple variants
{
  "id": "variants",
  "label": "Variants",
  "component": "IconPreview",
  "props": {
    "label": "",
    "icons": [
      { "label": "Default", "variant": "default", "colorScheme": "primary" },
      { "label": "Subtle", "variant": "subtle", "colorScheme": "primary" }
    ]
  }
}

The component field references the renderer name from the manifest. The propsobject must satisfy the renderer's schema — every editable field needs a .default(…) clause in the Zod definition so the showcase Content tab can hydrate the form.

The fastest way to add a variant is the /add-component-preview command. It generates the renderer file, the manifest entry, and a stub variant.json you can fill in. For an entirely new component (including the underlying implementation), use /create-component instead.

  • Showcase tour — how the Visual, Code, Recipe, and Content tabs use the variants you author.
  • Component tiers — which tiers actually carry variants (it's usually components and blocks).