JAVASCRIPT

Manage Dynamic Meta & Head Tags with Vue 3 Composable

Implement a Vue 3 composable (`useHeadTags`) to dynamically update document title and meta tags, crucial for SEO and social sharing in SPAs.

// composables/useHeadTags.js
import { watch, onMounted, onUnmounted } from 'vue';

const defaultTitle = 'My Awesome Vue App';
const defaultDescription = 'A general description of my Vue application.';

export function useHeadTags(options) {
  const updateHead = (opts) => {
    document.title = opts.title || defaultTitle;

    // Update meta description
    let metaDescription = document.querySelector('meta[name="description"]');
    if (!metaDescription) {
      metaDescription = document.createElement('meta');
      metaDescription.setAttribute('name', 'description');
      document.head.appendChild(metaDescription);
    }
    metaDescription.setAttribute('content', opts.description || defaultDescription);

    // You can extend this for other meta tags like Open Graph, Twitter cards, etc.
    // Example for OG Title:
    // let ogTitle = document.querySelector('meta[property="og:title"]');
    // if (!ogTitle) {
    //   ogTitle = document.createElement('meta');
    //   ogTitle.setAttribute('property', 'og:title');
    //   document.head.appendChild(ogTitle);
    // }
    // ogTitle.setAttribute('content', opts.ogTitle || opts.title || defaultTitle);
  };

  onMounted(() => {
    updateHead(options);
  });

  // You might want to watch reactive options if they change after mount
  if (options.title && typeof options.title === 'object' && 'value' in options.title) { // Check if it's a ref
    watch(options.title, (newTitle) => updateHead({ ...options, title: newTitle }), { immediate: true });
  }
  if (options.description && typeof options.description === 'object' && 'value' in options.description) { // Check if it's a ref
    watch(options.description, (newDesc) => updateHead({ ...options, description: newDesc }), { immediate: true });
  }


  onUnmounted(() => {
    // Optionally revert to default or previous values when component unmounts
    // For simple apps, often not strictly necessary as new routes will override
    document.title = defaultTitle;
    let metaDescription = document.querySelector('meta[name="description"]');
    if (metaDescription) {
      metaDescription.setAttribute('content', defaultDescription);
    }
  });

  return { updateHead }; // Expose updateHead if you want to manually trigger updates
}

// In your component:
/*
<template>
  <div>
    <h1>Welcome to {{ pageTitle }}</h1>
    <p>This page demonstrates dynamic head tag management.</p>
    <button @click="changeTitleAndDesc">Change SEO Info</button>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { useHeadTags } from '@/composables/useHeadTags'; // Adjust path

const pageTitle = ref('My Home Page');
const pageDescription = ref('This is the description for my home page.');

useHeadTags({
  title: pageTitle,
  description: pageDescription,
});

const changeTitleAndDesc = () => {
  pageTitle.value = 'Updated Page Title';
  pageDescription.value = 'This is a brand new description after an update!';
};
</script>
*/
How it works: This `useHeadTags` composable in Vue 3 allows for dynamic management of the document's `<head>` elements, specifically the title and meta description. When the component using this composable mounts, it updates these tags based on the provided options. It also includes `watch` effects to reactively update the head tags if the title or description `ref`s change. This is essential for Single Page Applications (SPAs) to ensure proper SEO, social media sharing previews, and user experience as they navigate different "pages." `onUnmounted` is used to revert to default values, though often the next route's `useHeadTags` will simply overwrite.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs