Even when you are a well practiced front end developer Sitecore Placeholders can be hard to grasp. Let's jump in it.

Sitecore placeholders do exactly what their name describe they "hold the place". A Sitecore Layout always starts with a root placeholder. Components can then be configured to show up on that placeholder. If those components on their turn have a placeholder inside. Then you can configure your components to have them linked to the descendant placeholder.

All of these principles work exactly the same in the regular MVC Sitecore framework and in the newer Sitecore JSS framework.

In the sample app of Sitecore JSS a root placeholder is defined by default. The "jss-main" placeholder is setup and the example "ContentBlock" component is already placed in it. If we simply search all for "jss-main", then we can see that it is referenced on the next 3 locations:

Route

The first location where it is referenced is on the route mocked data itself. Here you can define which components the placeholder will display when the route is rendered.

placeholders:
  jss-main:

Layout

The second location where "jss-main" can be found is on the layout. This is the place where all those components will show up in the page when it is rendered.

<Placeholder name="jss-main" rendering={route} />

Definition

The last location our search delivered is the placeholders definition file: "placeholders.sitecore.js". If you have experience in Sitecore pre-jss then this can be compared with the placeholder settings. Which is what this will become when deployed. If you don't have experience pre-jss, no worries, then simply put: This is the location where Sitecore has to know which placeholders he can find the routes and components.

manifest.addPlaceholder(
  { name: "jss-main", displayName: "Main" },
  // you can optionally pass a GUID or unique (app-wide) string as an ID
  // this will inform the ID that is set when imported into Sitecore.
  // If the ID is not set, an ID is created based on the placeholder name.
  { name: "jss-tabs", displayName: "Tabs", id: "tabs-placeholder" }
)

Root placeholders?

I know I said three, but too be exact: the actual last location where "jss-main" is found is inside the package.json "rootPlaceholders" config. When adding a placeholder into a component, this configuration doesn't really matter. If however you would like to create a new root placeholder, a new placeholder in the layout. Then this configuration is an important step. But for our example later on we can ignore it.

Our turn

Let's add our own placeholder now. We will add it into our existing "HelloWorld" component.

Route

Let's add it into the route. Simple add a new "placeholders" section underneath our component. In that placeholders section you can then define your new placeholder. In this case I've defined it with the very creative name: "jss-sub". Below that simply add a instance of our component.

placeholders:
  jss-main:
    - componentName: Hello-World
      fields:
        title: Hello World
      params:
        backgroundColor: green
      placeholders:
        jss-sub:
          - componentName: Hello-World
            fields:
                title: Hello World from inside the jss-sub placeholder
            params:
                backgroundColor: red

Layout/Component

As we saw the second step is to add into the layout, or in our case inside the components that needs it. Which leaves us with the following "HelloWorld" component

import React from "react"
import { Text, Placeholder } from "@sitecore-jss/sitecore-jss-react"

export default class HelloWorld extends React.Component {
  render() {
    let backgroundColorStyle = {
      backgroundColor: this.props.params.backgroundColor,
      padding: "20px",
    }
    return (
      <div style={backgroundColorStyle}>
        <Text tag="h1" field={this.props.fields.title} />
        <Placeholder name="jss-sub" rendering={this.props.rendering} />
      </div>
    )
  }
}

Definition

And then the last step is adding it into the "placeholders.sitecore.js" definition file.

manifest.addPlaceholder(
  { name: "jss-main", displayName: "Main" },
  { name: "jss-sub", displayName: "Sub" }
)

Let's refresh our page and look at the result:

We've successfully added a placeholder to our "HelloWorld" component and added that same component into it itself. Missed a step somewhere? You can always look it up in the commit that illustrates our steps taken here.