Search code examples
vue.jsnuxt.jsvue-meta

Nuxt.js: How to reference page data from a layout? (e.g., to populate og:title tags)


I'm using Nuxt.js to generate static pages. I want each page to have a unique <title> tag and <meta property="og:title" ... > tag.

Current implementation

I currently have an ugly solution that generates these tags. I have two pages that look like this:

pages/foo.vue

export default {
  head: {
    title: 'Foo',
    meta: [
      {
        property: 'og:title',
        content: 'Foo',
      },
    ],
  }
};

pages/bar.vue

export default {
  head: {
    title: 'Bar',
    meta: [
      {
        property: 'og:title',
        content: 'Bar',
      },
    ],
  }
};

Problem

This correctly generates <meta property="og:title" ...> tags for each of my pages, but it forces me to include redundant code on all of my pages. My og:title tag always matches my <title> tag, so it makes no sense to redefine each of them independently on every page.

Desired solution

I'd love a solution that allows me to define the og:title tag in my layouts/default.vue file or even in nuxt.config.js. Something like this:

layouts/default.vue

export default {
  head() {
    return {
      meta: [
        {
          property: 'og:title',
          content: this.$page.head.title, // <-- This variable doesn't really exist
        }
      ],
    };
  },
};

pages/foo.vue

export default {
  head: { title: 'Foo' }
};

pages/bar.vue

export default {
  head: { title: 'Bar' }
};

Question

Is is possible to eliminate the boilerplate here?

More generally, is it possible for Nuxt layouts to reference page-specific data?


Solution

  • A Layout.vue cannot directly access to the nuxt data from a Page.vue.
    You have to use a Store in order to share data between them.
    See https://nuxtjs.org/guide/vuex-store/


    About your initial request, you can use a Mixin to share your meta configuration on each Page.vue.
    See https://v2.vuejs.org/v2/guide/mixins.html

    eg.

    // mixins/meta.vue
    
    <script>
    export default {
      data () {
        return {
          title: null,
          description: null
        }
      },
      head () {
       return {
         title = this.title
         meta = [
          { hid: 'description', name: 'description', content: this.description },
          { hid: 'og:title', property: 'og:title', content: this.title },
          // ...
        ]
      }
    }
    </script>
    
    
    // <Page>.vue with local mixin
    
    <script>
    import Meta from '~/mixins/meta'
    
    export default {
      mixins: [Meta], // local mixin
      asyncData () {
        return {
          title: "Foo",
          description: "lorem ipsum",
        }
      }
    }
    </script>
    

    or create a global mixin with a Nuxt plugin:

    // plugins/meta.js
    
    import Vue from 'vue'
    
    Vue.mixin({
      data: { // ... }
      head: { // ...}
    })
    

    and declare your new plugin to apply on each Page:

    // nuxt.config.js
    
    plugins: ['~/plugins/meta'],