Gatsby: Is it possible to have 2 layouts?

Created on 13 Jul 2017  ·  12Comments  ·  Source: gatsbyjs/gatsby

hi, is it possible to have more than 1 layout? I searched issues, but can't find anything useful?

I tried #1119 method, use the code below:

 createPage({
                path: edge.node.fields.slug, // required
                component: blogPost,
                context: {
                    slug: edge.node.fields.slug,
                },
                layout: 'noFooter',
            })

but it doesn't work. Is there any examples or is it possible? thanks~

Most helpful comment

Again, for anybody searching here, I am using the following with success (slightly jury-rigged):

front-matter.js

// adapted from `front-matter` module
const yamlParser = require('js-yaml')

// extract /* @meta [YAML] */ comments
module.exports = function parse(string) {
    const match = /\/\*\s*@meta([\s\S]*?)\*\//.exec(string)

    if (!match) {
        return {
            attributes: {},
            body: string,
        }
    }

    const yaml = match[1].trim()
    const attributes = yamlParser.load(yaml) || {}
    const body = string.substr(match[0].length)
    return {attributes, body, frontmatter: yaml}
}

gatsby-node.js

const fm = require('./front-matter')
const fs = require(`fs-extra`)

exports.onCreatePage = async function({page}) {
    const {attributes: {layout}} = fm(await fs.readFile(page.component, 'utf8'))
    page.layout = layout || 'index'
}

With these in place, I can use frontmatter, like so:

src/pages/sample.js

/* @meta
layout: wide
*/
import React from 'react'
export default () => <div>...EXAMPLE...</div>

All 12 comments

Hey,

Atm it's currently not possible. I think @jbolda is working on it?

Two related issues: #1255 #1119

Finally I solved my problem by this code in layouts/index.jsx:

        {
          this.props.location.pathname === '/quickstart' ? '' : <Footer />
        }

Yea, currently that is the only way to do it. I just PRed my example with that. I was working on it, but had to stop for a while. Hoping someone else can pick it up.

https://github.com/gatsbyjs/gatsby/pull/1492/files

For anyone else that ends up here - it's possible to do this by implementing the onCreatePage API in your gatsby-node.js file. See https://www.gatsbyjs.org/docs/creating-and-modifying-pages/#choosing-the-page-layout

Again, for anybody searching here, I am using the following with success (slightly jury-rigged):

front-matter.js

// adapted from `front-matter` module
const yamlParser = require('js-yaml')

// extract /* @meta [YAML] */ comments
module.exports = function parse(string) {
    const match = /\/\*\s*@meta([\s\S]*?)\*\//.exec(string)

    if (!match) {
        return {
            attributes: {},
            body: string,
        }
    }

    const yaml = match[1].trim()
    const attributes = yamlParser.load(yaml) || {}
    const body = string.substr(match[0].length)
    return {attributes, body, frontmatter: yaml}
}

gatsby-node.js

const fm = require('./front-matter')
const fs = require(`fs-extra`)

exports.onCreatePage = async function({page}) {
    const {attributes: {layout}} = fm(await fs.readFile(page.component, 'utf8'))
    page.layout = layout || 'index'
}

With these in place, I can use frontmatter, like so:

src/pages/sample.js

/* @meta
layout: wide
*/
import React from 'react'
export default () => <div>...EXAMPLE...</div>

Just came across this issue whilst searching for a way to add multiple layouts.

Not sure if Gatsby has been updated since @jrop's helpful answer. But I found https://www.gatsbyjs.org/docs/creating-and-modifying-pages/#choosing-the-page-layout.

gatsby-node.js

const path = require("path");

exports.createPages = ({ boundActionCreators, graphql }) => {
  const { createPage } = boundActionCreators;

  return graphql(`
    {
      allMarkdownRemark {
        edges {
          node {
            excerpt(pruneLength: 400)
            html
            id
            frontmatter {
              templateKey
              path
              layout
              title
            }
          }
        }
      }
    }
  `).then(result => {
    if (result.errors) {
      result.errors.forEach(e => console.error(e.toString()));
      return Promise.reject(result.errors);
    }

    return result.data.allMarkdownRemark.edges.forEach(({ node }) => {
      const pagePath = node.frontmatter.path;
      const layout = node.frontmatter.layout || "index";

      createPage({
        path: pagePath,
        layout,
        component: path.resolve(
          `src/templates/${String(node.frontmatter.templateKey)}.js`
        )
        // additional data can be passed via context
        // context: {
        // }
      });
    });
  });
};

exports.onPreBootstrap = () => {
  require("isomorphic-fetch");
};

The key lines are here...

const layout = node.frontmatter.layout || "index";

      createPage({
        path: pagePath,
        layout,

It assumes your main layout file is index.jsx

src/pages/sample.md

templateKey: 'sample-page'
path: /sample
layout: NEW_LAYOUT_FILE_NAME
title: Sample
---

Then just add NEW_LAYOUT_FILE_NAME.jsx to your layout folder, restart the server and you should be good to go.


Update 11/04/2018
This breaks the build when deploying to Netlify due to https://github.com/gatsbyjs/gatsby/issues/1846

Update 11/04/2018
Turns out this does actually work! The build was breaking due to another issue 🙄

@gilesbutler

Can you add

templateKey: 'sample-page'
path: /sample
layout: NEW_LAYOUT_FILE_NAME
title: Sample
---

to a JS file? isn't this for MarkDown?

Good spot @PolGuixe 👍

I've updated my example src/pages/sample.js should have been src/pages/sample.md

@gilesbutler How would you use it in .js files?

You can't as far as I know. It was a typo and was supposed to be for MarkDown.

If you just need to make small changes, I just use conditional rendering.

{post.frontmatter.tag == 'blog' && <p className="project-cat"> — {post.frontmatter.date}</p> }

For anyone else that ends up here - it's possible to do this by implementing the onCreatePage API in your gatsby-node.js file. See https://www.gatsbyjs.org/docs/creating-and-modifying-pages/#choosing-the-page-layout

I cannot anything find at this link which corresponds with "Choosing ghe page layout". Did Gatsby changed the content? is there a "2020" approach or plugin?

Was this page helpful?
0 / 5 - 0 ratings