{"id":13393599,"url":"https://github.com/staylor/react-helmet-async","last_synced_at":"2025-05-13T20:10:51.813Z","repository":{"id":37602199,"uuid":"115991024","full_name":"staylor/react-helmet-async","owner":"staylor","description":"Thread-safe Helmet for React 16+ and friends","archived":false,"fork":false,"pushed_at":"2024-08-10T09:56:17.000Z","size":1469,"stargazers_count":2215,"open_issues_count":78,"forks_count":171,"subscribers_count":13,"default_branch":"main","last_synced_at":"2025-05-08T22:39:07.446Z","etag":null,"topics":["helmet","react","reactjs"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/staylor.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-01-02T08:08:47.000Z","updated_at":"2025-05-08T14:57:12.000Z","dependencies_parsed_at":"2023-02-08T05:31:33.858Z","dependency_job_id":"71e3ce87-99b8-4edb-9d6d-b20faddf9c90","html_url":"https://github.com/staylor/react-helmet-async","commit_stats":{"total_commits":128,"total_committers":27,"mean_commits":"4.7407407407407405","dds":0.3671875,"last_synced_commit":"eb63f20e205f1d8b9009c04bc3a7e2766a8d64d8"},"previous_names":["nytimes/react-helmet-async"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/staylor%2Freact-helmet-async","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/staylor%2Freact-helmet-async/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/staylor%2Freact-helmet-async/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/staylor%2Freact-helmet-async/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/staylor","download_url":"https://codeload.github.com/staylor/react-helmet-async/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254020609,"owners_count":22000754,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["helmet","react","reactjs"],"created_at":"2024-07-30T17:00:56.716Z","updated_at":"2025-05-13T20:10:51.776Z","avatar_url":"https://github.com/staylor.png","language":"TypeScript","funding_links":[],"categories":["JavaScript","UI Utilities","TypeScript"],"sub_categories":["Meta Tags"],"readme":"# react-helmet-async\n\n[![CircleCI](https://circleci.com/gh/staylor/react-helmet-async.svg?style=svg)](https://circleci.com/gh/staylor/react-helmet-async)\n\n[Announcement post on Times Open blog](https://open.nytimes.com/the-future-of-meta-tag-management-for-modern-react-development-ec26a7dc9183)\n\nThis package is a fork of [React Helmet](https://github.com/nfl/react-helmet).\n`\u003cHelmet\u003e` usage is synonymous, but server and client now requires `\u003cHelmetProvider\u003e` to encapsulate state per request.\n\n`react-helmet` relies on `react-side-effect`, which is not thread-safe. If you are doing anything asynchronous on the server, you need Helmet to encapsulate data on a per-request basis, this package does just that.\n\n## Usage\n\n**New is 1.0.0:** No more default export! `import { Helmet } from 'react-helmet-async'`\n\nThe main way that this package differs from `react-helmet` is that it requires using a Provider to encapsulate Helmet state for your React tree. If you use libraries like Redux or Apollo, you are already familiar with this paradigm:\n\n```javascript\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport { Helmet, HelmetProvider } from 'react-helmet-async';\n\nconst app = (\n  \u003cHelmetProvider\u003e\n    \u003cApp\u003e\n      \u003cHelmet\u003e\n        \u003ctitle\u003eHello World\u003c/title\u003e\n        \u003clink rel=\"canonical\" href=\"https://www.tacobell.com/\" /\u003e\n      \u003c/Helmet\u003e\n      \u003ch1\u003eHello World\u003c/h1\u003e\n    \u003c/App\u003e\n  \u003c/HelmetProvider\u003e\n);\n\nReactDOM.hydrate(\n  app,\n  document.getElementById(‘app’)\n);\n```\n\nOn the server, we will no longer use static methods to extract state. `react-side-effect`\nexposed a `.rewind()` method, which Helmet used when calling `Helmet.renderStatic()`. Instead, we are going\nto pass a `context` prop to `HelmetProvider`, which will hold our state specific to each request.\n\n```javascript\nimport React from 'react';\nimport { renderToString } from 'react-dom/server';\nimport { Helmet, HelmetProvider } from 'react-helmet-async';\n\nconst helmetContext = {};\n\nconst app = (\n  \u003cHelmetProvider context={helmetContext}\u003e\n    \u003cApp\u003e\n      \u003cHelmet\u003e\n        \u003ctitle\u003eHello World\u003c/title\u003e\n        \u003clink rel=\"canonical\" href=\"https://www.tacobell.com/\" /\u003e\n      \u003c/Helmet\u003e\n      \u003ch1\u003eHello World\u003c/h1\u003e\n    \u003c/App\u003e\n  \u003c/HelmetProvider\u003e\n);\n\nconst html = renderToString(app);\n\nconst { helmet } = helmetContext;\n\n// helmet.title.toString() etc…\n```\n\n## Streams\n\nThis package only works with streaming if your `\u003chead\u003e` data is output outside of `renderToNodeStream()`.\nThis is possible if your data hydration method already parses your React tree. Example:\n\n```javascript\nimport through from 'through';\nimport { renderToNodeStream } from 'react-dom/server';\nimport { getDataFromTree } from 'react-apollo';\nimport { Helmet, HelmetProvider } from 'react-helmet-async';\nimport template from 'server/template';\n\nconst helmetContext = {};\n\nconst app = (\n  \u003cHelmetProvider context={helmetContext}\u003e\n    \u003cApp\u003e\n      \u003cHelmet\u003e\n        \u003ctitle\u003eHello World\u003c/title\u003e\n        \u003clink rel=\"canonical\" href=\"https://www.tacobell.com/\" /\u003e\n      \u003c/Helmet\u003e\n      \u003ch1\u003eHello World\u003c/h1\u003e\n    \u003c/App\u003e\n  \u003c/HelmetProvider\u003e\n);\n\nawait getDataFromTree(app);\n\nconst [header, footer] = template({\n  helmet: helmetContext.helmet,\n});\n\nres.status(200);\nres.write(header);\nrenderToNodeStream(app)\n  .pipe(\n    through(\n      function write(data) {\n        this.queue(data);\n      },\n      function end() {\n        this.queue(footer);\n        this.queue(null);\n      }\n    )\n  )\n  .pipe(res);\n```\n\n## Usage in Jest\nWhile testing in using jest, if there is a need to emulate SSR, the following string is required to have the test behave the way they are expected to.\n\n```javascript\nimport { HelmetProvider } from 'react-helmet-async';\n\nHelmetProvider.canUseDOM = false;\n```\n\n## Prioritizing tags for SEO\n\nIt is understood that in some cases for SEO, certain tags should appear earlier in the HEAD. Using the `prioritizeSeoTags` flag on any `\u003cHelmet\u003e` component allows the server render of react-helmet-async to expose a method for prioritizing relevant SEO tags.\n\nIn the component:\n```javascript\n\u003cHelmet prioritizeSeoTags\u003e\n  \u003ctitle\u003eA fancy webpage\u003c/title\u003e\n  \u003clink rel=\"notImportant\" href=\"https://www.chipotle.com\" /\u003e\n  \u003cmeta name=\"whatever\" value=\"notImportant\" /\u003e\n  \u003clink rel=\"canonical\" href=\"https://www.tacobell.com\" /\u003e\n  \u003cmeta property=\"og:title\" content=\"A very important title\"/\u003e\n\u003c/Helmet\u003e\n```\n\nIn your server template:\n\n```javascript\n\u003chtml\u003e\n  \u003chead\u003e\n    ${helmet.title.toString()}\n    ${helmet.priority.toString()}\n    ${helmet.meta.toString()}\n    ${helmet.link.toString()}\n    ${helmet.script.toString()}\n  \u003c/head\u003e\n  ...\n\u003c/html\u003e\n```\n\nWill result in:\n\n```html\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003ctitle\u003eA fancy webpage\u003c/title\u003e\n    \u003cmeta property=\"og:title\" content=\"A very important title\"/\u003e\n    \u003clink rel=\"canonical\" href=\"https://www.tacobell.com\" /\u003e\n    \u003cmeta name=\"whatever\" value=\"notImportant\" /\u003e\n    \u003clink rel=\"notImportant\" href=\"https://www.chipotle.com\" /\u003e\n  \u003c/head\u003e\n  ...\n\u003c/html\u003e\n```\n\nA list of prioritized tags and attributes can be found in [constants.ts](./src/constants.ts).\n\n## Usage without Context\nYou can optionally use `\u003cHelmet\u003e` outside a context by manually creating a stateful `HelmetData` instance, and passing that stateful object to each `\u003cHelmet\u003e` instance:\n\n\n```js\nimport React from 'react';\nimport { renderToString } from 'react-dom/server';\nimport { Helmet, HelmetProvider, HelmetData } from 'react-helmet-async';\n\nconst helmetData = new HelmetData({});\n\nconst app = (\n    \u003cApp\u003e\n      \u003cHelmet helmetData={helmetData}\u003e\n        \u003ctitle\u003eHello World\u003c/title\u003e\n        \u003clink rel=\"canonical\" href=\"https://www.tacobell.com/\" /\u003e\n      \u003c/Helmet\u003e\n      \u003ch1\u003eHello World\u003c/h1\u003e\n    \u003c/App\u003e\n);\n\nconst html = renderToString(app);\n\nconst { helmet } = helmetData.context;\n```\n\n## License\n\nLicensed under the Apache 2.0 License, Copyright © 2018 Scott Taylor\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstaylor%2Freact-helmet-async","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstaylor%2Freact-helmet-async","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstaylor%2Freact-helmet-async/lists"}