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.