How to use dynamic layouts in a headless Sitecore application

Posted 03/11/2022 by Albraa Nabelsi

What if you have a headless site with more than one layout? There was an excellent article about this online, but I can’t find it anymore. I am documenting the required steps in case someone needs this in the future. We will explore how to do this in a headless application using a standard React JSS app.

Let us start by inspecting RouteHandler.js, notice the following:

1) The layout file is always loaded from Layout.js (line 12)

2) The layout is rendered if the page is found (line 170)

We will need to make this process dynamic if we want to create multiple layouts.

First, start by creating a new folder under the /src folder called ‘layouts’

  1. Move the /src/Layout.js file to the /src/layouts folder
  2. You can rename the file to DefaultLayout.js as this will be the fallback file in case the app is not able to find your custom layout
  3. Create your custom layout under the ‘layouts’ folder
  4. Create an index.js file to export all of the layouts

You should have something like this in the end:

Now, we need to map the layout files to the layouts in Sitecore. Under the src/ folder, start by creating a file called LayoutFactory.js with the following code:

import * as layouts from './layouts';

class LayoutFactory {
  constructor() {
    this.layoutMap = new Map();
    this.layoutMap.set('{3596B70A-8AFC-4E8D-9044-8857401C4374}', layouts.TestLayout);
    this.layoutMap.set('default', layouts.DefaultLayout);
  }

  resolveLayout(routeData) {
    const layoutId = `{${routeData.layoutId.toUpperCase()}}`;
    const layout = this.layoutMap.get(layoutId);

    return layout || this.layoutMap.get('default');
  }
}

const layoutFactory = new LayoutFactory();

Object.freeze(layoutFactory);
export default layoutFactory;

The file checks the layoutId in the routeData. If the layoutId in the route matches the ID of mapped layout, then that layout will be returned – if no matches are found, then the default layout will be returned instead. Note that in the example above, '{3596B70A-8AFC-4E8D-9044-8857401C4374}' was the ID of my custom layout.

We have all the pieces ready. we just need to update the RouteHandler.js file like this:

Note that now, instead of loading the layout, we are passing the route data to the LayoutFactory, and it is returning the layout file based on the layoutId in the route data.

For NextJS

The process is almost identical for Next.JS apps, except you will need to work on the [[…path]].tsx file instead of the RouteHandler.js: