Placeholder Maintenance with Sitecore Content SDK A developer working with Sitecore's Content SDK during a migration from JSS to XM Cloud encountered a challenge where server components cannot be placed inside a client component's placeholder. The solution involves creating a server component wrapper that owns the AppPlaceholder, allowing the Sitecore editor to insert any component type, while the client component handles interactivity. During the conversion process from JSS to Content SDK for Sitecore AI IE XM Cloud , there's some changes to how components are designated and mapped to be aware of, which affect how placeholders work and how those components work inside the placeholders. This led to our needing a solution to handle placeholders in certain circumstances. The component designation in Content SDK separates server from client components. This separation is determined by the use of hooks in the code like useEffect and a component is made "client" by placing "use client" in the first line of the component. Technically you could make every component "client" but you lose out on benefits of server components. When it comes to Sitecore, there's a useSitecore hook that can be used for getting things like the editing state. But you don't need to use that hook, because the new placeholder model, called AppPlaceholder , that passes the page model down from one level to the next. That includes the edit state, so you can access it in server components as well. This starts all the way up in your Layout.tsx file, which you'll see in the starter kit you can download from Github https://github.com/Sitecore/xmcloud-starter-js , and it's a required parameter so it'll always be passed down. You cannot bring server components into a placeholder under a client component. Sitecore has documentation on this. https://doc.sitecore.com/sai/en/developers/content-sdk/20/manage-component-maps-for-client-and-server-components.html import-component-map-in-client-components It'll work if you set things up manually, but in Pages you won't be allowed to pull components in. To be clear, the scenario is you have a component - let's say a tabs component - that has an AppPlaceholder on it. The tabs component will typically have some hooks to handle click changes between the tabs, and that requires "use client" to be designated. Then you'll have a tabs panel component, which you pull in to set up each individual tab, and that also has AppPlaceholder to hold a variety of other components. Then you might pull in a rich text component, which is likely a server component because it has no hooks. If you just do that straight away, like you would have in JSS, you won't be able to bring those server components in. I'll say a solution because I'm sure there's others, and the documentation suggests something, but it wasn't entirely clear to me. What I worked out with some research, AI, and trial and error, was this solution. The solution boils down to this: if you have a component that has AppPlaceholder and needs to be a client component as well, you have a client/server tag team. The server component part is the actual component you'll be registering in Sitecore as a rendering. It might look something like this: js import { type JSX } from "react"; import { AppPlaceholder } from "@sitecore-content-sdk/nextjs"; import componentMap from ".sitecore/component-map"; import TabsClient from "./TabsClient"; import type { TabsProps } from "./Tabs.types"; / Tabs — server component wrapper. Owns AppPlaceholder so the Sitecore editor treats the placeholder as server-owned and allows inserting any component type server or client . Edit mode: renders the placeholder in a single column with a label. Normal mode: passes pre-rendered placeholder content as RSC children to TabsClient, which handles mobile detection and DOM manipulation for the horizontal tab navigation. / export default function Tabs { rendering, params, page }: TabsProps : JSX.Element { const isPageEditing = page?.mode?.isEditing ?? false; const phKey = tabs-${params?.DynamicPlaceholderId ?? ""} ; const content =