If you’ve ever dropped a perfectly valid Sitecore rendering into a nested <Placeholder> and watched Pages Builder (or your local app) complain that it can’t find the component in component-map.client, you’re not alone — and you’re probably not looking in the wrong place.
This post walks through a real debugging session from an XM Cloud / Sitecore Content SDK Next.js App Router site: adding a Video rendering inside an Interior Media Hero Banner placeholder. The component existed. The GraphQL query existed. The Sitecore rendering componentName was set. And yet the client still couldn’t resolve it.
Authors could insert a Video rendering into that slot. On the frontend, resolution failed with an error implying the component was missing from the client component map.
That wording matters. It didn’t say “Video is not registered.” It pointed specifically at component-map.client.
The wrong first instincts (and why they’re reasonable)
Before finding the real issue, it’s easy to chase:
- Placeholder name mismatch — interior-media-{DynamicPlaceholderId} vs Sitecore Placeholder Settings
- Missing Placeholder Settings / dynamic placeholder flags on the parent rendering
- Wrong componentName on the Video JSON/YAML
- Component map not regenerated after adding files
- Video GraphQL/datasource issues
- Those can all be real problems. In our case, they weren’t the ones throwing the client-map error.
A useful clue: the same placeholder pattern already worked elsewhere in the project for Resource Promo, which nests child renderings into named placeholders. So placeholders themselves weren’t broken.
The architecture that actually matters
In this Next.js App Router setup, there are (at least) two maps:
| Map | Typical file | Used for |
|---|---|---|
| Full / server map | .sitecore/component-map.ts | App layout resolution, broader server rendering |
| Client map | .sitecore/component-map.client.ts | What SitecoreProvider hands to client-side placeholder resolution |
The app provider looked essentially like this:
That means when you use the Content SDK’s <Placeholder> component, nested renderings are resolved against component-map.client.ts, not the full server map.
Meanwhile, Layout / AppPlaceholder patterns can still use the fuller component-map.ts.
So you can have:
- Video registered in component-map.ts
- Video missing from component-map.client.ts
- Nested <Placeholder> fails
That’s the trap.
Why is the client map smaller?
Important nuance:
Making the UI component a client component does not automatically put the Sitecore wrapper on the client component map.
Sitecore resolves by rendering componentName → wrapper export in the map. The map generation cares about the Sitecore wrapper module’s client boundary, not whether some child React tree eventually needs hooks.
Two valid fixes
Option A — Make the nested rendering a client Sitecore wrapper (common for interactive widgets)
- Add "use client"; to the Sitecore wrapper (Video.tsx)
- Regenerate maps (sitecore-tools:generate-map / sitecore-tools:build depending on your pipeline)
- Confirm Video appears in .sitecore/component-map.client.ts
- Confirm related symbols appear in .sitecore/import-map.client.ts if your setup uses import maps
Choose this when:
- the component is interactive (modals, players, state)
- you intentionally want it available anywhere <Placeholder> resolves client-side
- editing/preview chrome depends on client hydration for that nested branch
Option B — Resolve with AppPlaceholder + the server map (Container-style)
Some wrappers already do this:
Choose this when:
- you want to keep the child wrapper as a server component
- the parent already has page and can supply the full map
- you’re mirroring an established container pattern in the repo
Neither fix is “more correct” universally. They’re different seams in the same architecture.
Authoring checklist (related, but separate)
Even after the map issue is fixed, dynamic placeholders still need Sitecore-side wiring:
- Placeholder Settings with a key like interior-media-{*}
- Parent rendering flags such as IsRenderingsWithDynamicPlaceholders=true
- Parent rendering Placeholders field linking those settings
- Child rendering componentName matching the map key (Video, InteriorMediaHeroBanner, etc. — avoid accidental spaces like Interior Media Hero Banner if the map key is PascalCase)
Those issues usually show up as empty slots or authoring constraints. The client-map error is the giveaway that resolution never found the React module on the map your provider uses.
A practical debugging checklist for the future
When a nested rendering fails with a client-map message:
- Search both maps for the componentName
- If present only in component-map.ts, you’ve found the mismatch
- Check whether the Sitecore wrapper has "use client"
- Compare with a working nested child in the same repo
- Decide: promote wrapper to client or resolve via server AppPlaceholder
- Rebuild Sitecore maps and retest in normal + editing modes
Don’t start by rewriting GraphQL until the map lookup succeeds.
Takeaway
In Sitecore Content SDK App Router apps, placeholder resolution is only as capable as the component map you hand to SitecoreProvider.
If that map is the client map, then every nested rendering must be client-map eligible — usually by being a client Sitecore wrapper — unless you deliberately resolve that slot with the fuller server map.
The Video-in-hero failure wasn’t mysterious once we asked one question:
Which map is this Placeholder using — and is my child actually on it?
That question will save you hours.
Helpful resources
Sitecore / XM Cloud / Content SDK
- Sitecore Content SDK for XM Cloud documentation
- Sitecore configuration file (defineConfig)
- Sitecore XM Cloud developer documentation
- Placeholder settings overview (XM Cloud) (confirm current path in XM Cloud docs if the nav shifts)
Next.js App Router / client boundaries

No comments:
Post a Comment