import React from "react";
import { Helmet } from "react-helmet";
const HotelHelmet = ({
title,
address,
images,
websiteSlug,
city,
state,
descriptions,
keywords,
}) => {
return (
<Helmet>
<title>{title}</title>
<meta name="description" content={descriptions} />
<meta name="keywords" content={keywords} />
<meta property="og:title" content={title} />
<meta property="og:image" content={images[0]?.cdnImageUrl} />
<meta property="og:description" content={descriptions} />
<link rel="preload" as="image" href={images[0]?.cdnImageUrl} />
</Helmet>
);
};
export default HotelHelmet;
I'm getting all the data dynamically from DB but I'm not able to see the link preview with updated values while sharing the values in social media. Instead the default values set is being displayed but I want to display the updated values in the preview.
Thank you.
I'm developing my website with Next.js To upgrade my website's SEO performance, I'm trying to avoid duplicated meta tags.
My Question
In Next official docs, they say that I can avoid overlapped meta tag by insert key property in meta tag. But this does not work.
<meta name="description" content="~~" key="titleDescription"/>
<meta name="keywords" content="~~" key="titleKeywords"/>
These are default rootDocument meta tags and,
<meta name="description" content={item.product_description} key="titleDescription"></meta>
<meta name="keywords" content={item.brand_name} key="titleKeywords"></meta>
These are dynamically generated meta tags in item pages.
In deployed browser, there are still two description and keywords meta tags in website. I want to avoid duplicated meta tag. Thank you for your help!
There are a few things to watch for when using Next.js Head components.
The _document Head component is next/document
Tags in _document will not be replaced (can be duplicated) even with a key identifier
The _app Head component is next/head
Tags in _app can be in child components
Tags in _app can be overridden with the key identifier
Tags in pages cannot be in child components
Tags in pages can override tags with the same key identifier.
Examples
_document.{js|jsx|ts|tsx}
Scripts, styles, and other tags you need access to immediately - Next will likely not be fully mounted at this point. You cannot replace tags in the document/head component with the key attribute.
import Document, {Head, Html, Main, NextScript } from 'next/document';
class MyDocument extends Document {
render = () => (
<Html lang="en-US" dir="ltr">
<Head>
<script src="/some-script.js" defer={false} />
<style>.inline-styles{}</style>
{/* META & TITLE TAGS PLACED HERE CANNOT BE OVERRODE */}
</Head>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
OR self-closing Head tag
class MyDocument extends Document {
render = () => (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
Note: import is from next/document
_app.{js|jsx|ts|tsx}
import Head from 'next/head';
const App = ({ Component, pageProps }) => (
<>
<Head>
<title key="title">App Tittle</title>
</Head>
<Component {...pageProps} />
</>
);
OR load from a custom component
import Head from 'next/head';
const MyHeadTags = () => (
<Head>
<title key="title">App Tittle</title>
<meta key="description" name="description">Description</meta>
</Head>
);
const App = ({ Component, pageProps }) => (
<>
<MyHeadTags />
<Component {...pageProps} />
</>
);
Note: import is from next/head
some_page.{js|jsx|ts|tsx}
const SomePage = () => (
<>
<Head>
<title key="title">Some Page Tittle</title>
<meta key="description" name="description">Some Page Description</meta>
</Head>
<div>My Page</div>
</>
);
NOT ALLOWED
The head component must be on the page and cannot be a child component. If it's a child component, it sometimes will not override other tags with the same key property.
some_page.{js|jsx|ts|tsx}
const MyHeadTags = () => (
<Head>
<title key="title">Some Page</title>
<meta key="description" name="description">Some Page Description</meta>
</Head>
);
const ChildComponent = () => (
<>
<MyHeadTags />
Info.
</>
);
const SomePage= () => (
<>
<ChildComponent />
<div>Will not work</div>
</>
);
Update: The last example seems to work in some cases with Next 11+, but I have run into a few instances where it duplicates tags. I avoid the last method.
UPDATE
Here's what Next.js docs say regarding the <Head /> element within the _document.js file:
The component used here is not the same one from next/head.
The component used here should only be used for any
code that is common for all pages. For all other cases, such as
<title> tags, we recommend using next/head in your pages or
components.
Source: https://nextjs.org/docs/advanced-features/custom-document
Therefore, Next.js recommends that all the dynamic <meta /> tags should only be defined on an individual page level.
ORIGINAL ANSWEAR (it seemed to work at first, but as it turns out, only at random).
This issue seems to appear when you mix up two ways of closing empty HTML tags in JSX. Notice that your meta tags in the _document.js file are self-closing: <meta /> and the dynamic ones are not: <meta></meta>.
Ensure you are consistent with it (i.e. according to best practices you should convert all empty tags to the self-closing variant) and you should be fine.
I believe you can take a look at this package that helps managing meta tags https://github.com/garmeeh/next-seo in Next.js project. It helped me :D
For your question, yea try putting the Head in the _app instead of _document. _document is like non mutated one.. it will be always in the website. Cheers 🥂
I use Next 12.
Thanks to Sean's comment here, I was able to progress.
I personally update the tags for SEO purpose according to the consulted page with a component Seo that I crafted.
But to prevent importing it in every pages, I wanted to import it once. It happened that importing this Seo component in pages/_app.js was eventually just duplicating the tags and especially breaking my social media links.
So here is my code.
First the Seo component:
import Head from 'next/head'
import {SEO} from '#/Constants/seo'
const titlePrepend = 'WeekandGO | '
const Seo = ({ seo }) => {
const currentUrl = typeof window !== 'undefined' && window.location.href
const defaultSeo = {...SEO['index']}
let seoWithDefaults = {...defaultSeo}
if (seo) {
seoWithDefaults = {
...seoWithDefaults,
...seo,
}
}
const fullSeo = {
...seoWithDefaults,
metaTitle: seoWithDefaults?.metaTitle ? `${titlePrepend}${seoWithDefaults.metaTitle}` : `${titlePrepend}${defaultSeo.metaTitle}`,
shareImage: seoWithDefaults?.shareImage || defaultSeo.shareImage,
metaDescription: seoWithDefaults?.metaDescription || defaultSeo.metaDescription,
}
return <Head>
<title>{fullSeo.metaTitle}</title>
<meta name="Author" lang="fr" content="Leb Communication"/>
<meta name="Identifier-URL" content="www.weekandgo.com"/>
<meta name="Reply-to" content=""/>
<meta name="revisit-after" content="7"/>
<meta name="Publisher" content="WeekandGO"/>
<meta name="Copyright" content="WeekandGO"/>
<link rel="canonical" href="https://www.weekandgo.com/" />
<meta name="keywords" content={fullSeo.metaKeywords} />
<meta name="description" content={fullSeo.metaDescription} />
<meta name="image" content={fullSeo.shareImage} />
<meta property="og:site_name" content="WeekandGO" />
<meta property="og:url" content={currentUrl || 'https://www.weekandgo.com/'} />
<meta property="og:type" content="website" />
<meta property="og:image" content={fullSeo.shareImage} />
<meta property="og:title" content={fullSeo.metaTitle} />
<meta property="og:description" content={fullSeo.metaDescription} />
<meta name="twitter:title" content={fullSeo.metaTitle} />
<meta name="twitter:description" content={fullSeo.metaDescription} />
<meta name="twitter:image" content={fullSeo.shareImage} />
</Head>
}
export default Seo
I use it in pages/_document.js:
class MyDocument extends Document {
render() {
return (
<Html lang="fr">
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
<meta name="theme-color" content="#000000" />
<link rel="apple-touch-icon" href="/logo192.png" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap&subset=latin-ext" rel="stylesheet" />
<link rel="stylesheet" href="https://use.typekit.net/uah4cdm.css" />
<link rel="manifest" href="/manifest.json" />
<script src="https://maps.googleapis.com/maps/api/js?key=<key>" type="text/javascript"/>
</Head>
<Seo/>
<body className={ !isMobile && 'u-hover-on'}>
<Main />
<NextScript />
</body>
</Html>
)
}
}
Then I import this component in pages/_document.js as so:
import Document, { Html, Head, Main, NextScript } from 'next/document'
import { isMobile } from 'react-device-detect'
import Seo from '#/Shared/Seo'
class MyDocument extends Document {
render() {
return (
<Html lang="fr">
<Head>
<link rel="icon" href="/favicon.ico" />
<meta name="theme-color" content="#000000" />
<link rel="apple-touch-icon" href="/logo192.png" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap&subset=latin-ext" rel="stylesheet" />
<link rel="stylesheet" href="https://use.typekit.net/uah4cdm.css" />
<link rel="manifest" href="/manifest.json" />
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDiB40c-5x-GAEBw3mIJXPTvamFHUV536I" type="text/javascript"/>
</Head>
<Seo/>
<body className={ !isMobile && 'u-hover-on'}>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
Then, let me spare you some lines to just look at the return of my functional component App in pages/_app.js. There is no import of Seo component, only a ** Head coming from 'next/head' ** is used :
...
return (<SessionProvider session={session}>
<TokensRefresher/>
<Head>
<meta charSet="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</Head>
<GlobalContextProvider appProps={{ global, categoryAnnexes, categoriesInfos }}>
<GlobalLayout error={error}>
<Component {...rest} />
</GlobalLayout>
</GlobalContextProvider>
</SessionProvider>)
}
...
And finally, here is a page I receive data from server side props and that I want to use to change the meta tags related to seo. Here again I don't show the part of the code that are useless for the matter :
...
const Annonce = ({ ad, ...pageProps }) => {
return <>
<Seo seo={{metaTitle: ad?.slug, metaDescription: ad?.dealerWord, shareImage: ad?.firstImage?.fileUrl}} />
<AnnonceLayout ad={ad} {...pageProps} />
</>
}
...
The result I have in the source code is there is no duplicated meta tags and I can share my links on social medias with no image, description or page tilte overlaps
I am trying to share images and video on social media ( mostly FB,twitter,linkedIn )in reactjs app , have added react-helmet for the same but still unable to share image below is the link which i am referring and my code.
https://medium.com/camperstribe/react-social-media-integration-with-react-share-and-react-helmet-84d9def6a445
Above solution is not working
import React from "react";
import { Helmet } from "react-helmet";
// import { useLocation } from "react-router-dom";
export default function HelmetMetaData(props) {
// let location = useLocation();
let quote = props.quote !== undefined ? props.quote : "";
let title =
props.title !== undefined
? props.title
: "CampersTribe - World is yours to explore";
let image =
props.image !== undefined
? props.image
: "https://images.unsplash.com/photo-1576091160550-2173dba999ef?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=2850&q=80";
let description =
props.description !== undefined
? props.description
: "CampersTribe lets you experience the camping culture. We discover the hidden gems in the nearby to help you connect with nature & yourself by learning in the woods, on the riverbank under the open sky." +
"Trust us, its million dollars experience to ride away from city life, pitch a tent, do campfire and endless talk!" +
"So, join us on this voyage, and explore the beauty and miracle of being yourself!";
let hashtag = props.hashtag !== undefined ? props.hashtag : "#camperstribe";
return (
<Helmet>
<title>{title}</title>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="csrf_token" content="" />
<meta property="type" content="website" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta name="msapplication-TileColor" content="#ffffff" />
<meta name="msapplication-TileImage" content="/ms-icon-144x144.png" />
<meta name="theme-color" content="#ffffff" />
<meta name="_token" content="" />
<meta name="robots" content="noodp" />
<meta property="title" content={title} data-react-helmet="true"/>
<meta property="quote" content={quote} data-react-helmet="true"/>
<meta name="description" content={description} data-react-helmet="true"/>
<meta property="image" content={image} data-react-helmet="true"/>
<meta property="og:locale" content="en_US" />
<meta property="og:type" content="website" />
<meta property="og:title" content={title} />
<meta property="og:quote" content={quote} />
<meta property="og:hashtag" content={hashtag} />
<meta property="og:image" content={image} data-react-helmet="true"/>
<meta property="og:image:secure_url" content={image} data-react-helmet="true"/>
<meta content="image/*" property="og:image:type" data-react-helmet="true"/>
<meta property="og:site_name" content="CampersTribe" />
<meta property="og:description" content={description} />{" "}
</Helmet>
);
}
i have created helmetMetaData component and calling in top of my social share component
return (
<div className="app-content content">
<HelmetMetaData />
<FacebookShareButton
windowWidth="800"
windowHeight="500"
url={
"https://images.unsplash.com/photo-1576091160550-2173dba999ef?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=2850&q=80"
}
quote={"test sharing"}
image={
"https://images.unsplash.com/photo-1576091160550-2173dba999ef?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=2850&q=80"
}
imageURL={
"https://images.unsplash.com/photo-1576091160550-2173dba999ef?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=2850&q=80"
}
// hashtag="#camperstribe"
// className={classes.socialMediaButton}
>
<FacebookIcon size={36} />
</FacebookShareButton>
)
but not working only getting url and title on facebook share dialog,
anybody knows how to share image on social media in reactjs?
I know it's an old question, but try to insert image meta tag directly into public/index.html. As it said in this issue: adding meta on client side dynamically does not work. Crawlers (fb, tw, etc) can see only static html. And it seems like FacebookShareButton doesn't have image as an optional prop.
this is the app.js file
import React from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import DashboardLayout from './layouts/DashboardLayout';
import './faithdash/scss/styles.scss';
export default function App() {
return (
<BrowserRouter>
<Switch>
<Route component={DashboardLayout} />
</Switch>
</BrowserRouter>
);
}
this is the index.html file
ive tried everything and have used different my vscode index chrome previewer to view the index file like others but its shows a blank screen
<!DOCTYPE html>
<html lang="en">
<head>
<title> Faithpays dashboard</title>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.png" />
<link
href="https://%PUBLIC_URL%/evergreen.eot"
rel="font"
/>
<link
href="https://%PUBLIC_URL%/evergreen.css"
rel="stylesheet"
crossorigin="anonymous" />
</head>
<body>
<div id="app"></div>
<script src="app.js"></script>
<script src="_nav.js"></script>
</body>
</html>
Because you didn't call render function from ReactDOM.
See more here: https://reactjs.org/docs/getting-started.html
I'm using react-universally as a ReactJS application boilerplate and bootstrap 4 for styling. Here is the main component DemoApp:
import 'normalize.css/normalize.css';
import React from 'react';
import Switch from 'react-router-dom/Switch';
import Route from 'react-router-dom/Route';
import Helmet from 'react-helmet';
import config from '../../utils/config';
import './globals.css';
import Error404 from './Error404';
import Header from './Header';
import AsyncHomeRoute from './AsyncHomeRoute';
import AsyncCounterRoute from './AsyncCounterRoute';
import AsyncAboutRoute from './AsyncAboutRoute';
/// Should change the language below according to the user preference language
function DemoApp() {
return (
<div style={{ padding: '2rem' }}>
<Helmet>
<html lang="en" />
<title>{config('htmlPage.defaultTitle')}</title>
<meta name="application-name" content={config('htmlPage.defaultTitle')} />
<meta name="description" content={config('htmlPage.description')} />
<meta charSet="utf-8" />
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="msapplication-TileColor" content="#2b2b2b" />
<meta name="msapplication-TileImage" content="/favicons/mstile-144x144.png" />
<meta name="theme-color" content="#2b2b2b" />
{/*
A great reference for favicons:
https://github.com/audreyr/favicon-cheat-sheet
It's a pain to manage/generate them. I run both these in order,
and combine their results:
http://realfavicongenerator.net/
http://www.favicomatic.com/
*/}
<link
rel="apple-touch-icon-precomposed"
sizes="152x152"
href="/favicons/apple-touch-icon-152x152.png"
/>
<link
rel="apple-touch-icon-precomposed"
sizes="144x144"
href="/favicons/apple-touch-icon-144x144.png"
/>
<link
rel="apple-touch-icon-precomposed"
sizes="120x120"
href="/favicons/apple-touch-icon-120x120.png"
/>
<link
rel="apple-touch-icon-precomposed"
sizes="114x114"
href="/favicons/apple-touch-icon-114x114.png"
/>
<link
rel="apple-touch-icon-precomposed"
sizes="76x76"
href="/favicons/apple-touch-icon-76x76.png"
/>
<link
rel="apple-touch-icon-precomposed"
sizes="72x72"
href="/favicons/apple-touch-icon-72x72.png"
/>
<link
rel="apple-touch-icon-precomposed"
sizes="57x57"
href="/favicons/apple-touch-icon-57x57.png"
/>
<link
rel="apple-touch-icon-precomposed"
sizes="60x60"
href="/favicons/apple-touch-icon-60x60.png"
/>
<link
rel="apple-touch-icon"
sizes="180x180"
href="/favicons/apple-touch-icon-180x180.png"
/>
<link rel="mask-icon" href="/favicons/safari-pinned-tab.svg" color="#00a9d9" />
<link rel="icon" type="image/png" href="/favicons/favicon-196x196.png" sizes="196x196" />
<link rel="icon" type="image/png" href="/favicons/favicon-128.png" sizes="128x128" />
<link rel="icon" type="image/png" href="/favicons/favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/png" href="/favicons/favicon-32x32.png" sizes="32x32" />
<link rel="icon" sizes="16x16 32x32" href="/favicon.ico" />
<meta name="msapplication-TileColor" content="#2b2b2b" />
<meta name="msapplication-TileImage" content="/favicons/mstile-144x144.png" />
<meta name="msapplication-square70x70logo" content="/favicons/mstile-70x70.png" />
<meta name="msapplication-square150x150logo" content="/favicons/mstile-150x150.png" />
<meta name="msapplication-wide310x150logo" content="/favicons/mstile-310x150.png" />
<meta name="msapplication-square310x310logo" content="/favicons/mstile-310x310.png" />
<link rel="manifest" href="/manifest.json" />
{/*
NOTE: This is simply for quick and easy styling on the demo. Remove
this and the related items from the Content Security Policy in the
global config if you have no intention of using milligram.
*/}
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Tangerine"
/>
<link
rel="stylesheet"
href="/scripts/css/bootstrap.css"
/>
</Helmet>
<Header />
<div style={{ paddingTop: '2rem', paddingBottom: '2rem' }}>
<Switch>
<Route exact path="/" component={AsyncHomeRoute} />
<Route path="/counter" component={AsyncCounterRoute} />
<Route path="/about" component={AsyncAboutRoute} />
<Route component={Error404} />
</Switch>
</div>
</div>
);
}
export default DemoApp;
And my global.css file, that styles all the application:
html {
box-sizing: border-box;
font-family: 'Tangerine', serif !important;
color: red;
}
*,
*:before,
*:after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
/* Inline our ul for our menu */
ul {
margin: 0;
padding: 0;
list-style-type: none;
}
ul li { display: inline; margin: 0 .5rem; }
My problem is that the font set (Tangerine) is not being show. It is being applied but then overwritten by boostraps _reboot.css that sets all font to bootstrap default.
I can imagine that this is due to the import "./globals.css" command that is being executed before loading bootstrap, so when I load bootstrap it calls _reboot to reset all parameter, includind its font, overwriting my settings.
How can I, using the DemoApp shown component approach, invert that order and load globals.css after bootstrap complete its setup cycle, so that my fonts can be used with no problems ?
If not possible, is there other solution availabe to setup bootstrap variables globally in a ReactJS environment ?
Thanks for helping.
You globals.css should override the global bootstrap.css or at least be applied after bootstrap.css has been loaded.
Since the file is global, you could create a Link after bootstrap:
<link
rel="stylesheet"
href="/scripts/css/bootstrap.css"
/>
<link
rel="stylesheet"
href="/scripts/css/globals.css"
/>
Am I missing something?