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.
variant prop on a single function. The exported function name is the variant identifier Sitecore selects on.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
componentsandblocks).