### Development Commands
Source: https://github.com/staylor/react-helmet-async/blob/main/README.md
Standard commands for installing dependencies and running tests within the project.
```bash
pnpm install
pnpm test # unit tests
pnpm run test:e2e # server + browser e2e tests
pnpm run test:all # everything
```
--------------------------------
### Client-side and Server-side HelmetProvider Setup
Source: https://context7.com/staylor/react-helmet-async/llms.txt
Wraps the React tree to provide per-request Helmet state isolation. Required for React 16-18 on both client and server. On React 19, it's a transparent passthrough but should be included for forward compatibility. Pass a `context` object on the server to capture serialized head state.
```tsx
import React from 'react';
import { createRoot } from 'react-dom/client';
import { Helmet, HelmetProvider } from 'react-helmet-async';
createRoot(document.getElementById('root')!).render(
);
```
```tsx
import { renderToString } from 'react-dom/server';
import { Helmet, HelmetProvider } from 'react-helmet-async';
const helmetContext: { helmet?: any } = {};
const html = renderToString(
);
const { helmet } = helmetContext;
const fullHtml = `
`;
```
```tsx
import { HelmetProvider } from 'react-helmet-async';
HelmetProvider.canUseDOM = false; // force SSR mode in tests
```
--------------------------------
### Track DOM Updates with onChangeClientState
Source: https://context7.com/staylor/react-helmet-async/llms.txt
Use `onChangeClientState` to get a callback on every client-side head update. It provides the new state, added tags, and removed tags, useful for analytics or tag management.
```tsx
import { Helmet, HelmetProvider } from 'react-helmet-async';
import type { StateUpdate, HelmetTags } from 'react-helmet-async';
function TrackedPage() {
const handleHeadChange = (
newState: StateUpdate,
addedTags: HelmetTags,
removedTags: HelmetTags
) => {
if (addedTags.metaTags?.length) {
console.log('Meta tags added:', addedTags.metaTags.map(t => t.outerHTML));
}
if (removedTags.linkTags?.length) {
console.log('Link tags removed:', removedTags.linkTags.map(t => t.outerHTML));
}
// newState contains the full merged state:
// newState.title, newState.metaTags, newState.linkTags, etc.
window.dataLayer?.push({ event: 'helmetUpdate', title: newState.title });
};
return (
Tracked Page
);
}
// Callback receives:
// addedTags: { metaTags: [HTMLMetaElement], linkTags: [HTMLLinkElement] }
// removedTags: {} (nothing removed on first render)
```
--------------------------------
### SSR with toComponent() for React SSR Frameworks
Source: https://context7.com/staylor/react-helmet-async/llms.txt
Utilize the `toComponent()` method to get React elements for head tags, suitable for integration with React-based SSR frameworks like Next.js or Remix. This allows direct rendering of head elements within your React server components.
```tsx
import { renderToStaticMarkup } from 'react-dom/server';
const titleElement = helmet.title.toComponent();
// => [React.createElement('title', { 'data-rh': true }, 'My Page')]
const titleMarkup = renderToStaticMarkup(<>{titleElement}>);
// => 'My Page'
const htmlAttrsProps = helmet.htmlAttributes.toComponent();
// => { lang: 'en' } — spread directly onto in a React SSR document component
const bodyAttrsProps = helmet.bodyAttributes.toComponent();
// => {}
const metaComponents = helmet.meta.toComponent();
// => [React.createElement('meta', { 'data-rh': true, name: 'description', content: '...' }), ...]
```
--------------------------------
### Client-Side Helmet Usage with HelmetProvider
Source: https://github.com/staylor/react-helmet-async/blob/main/README.md
Import Helmet and HelmetProvider from 'react-helmet-async'. Wrap your application with HelmetProvider and use Helmet components to manage head tags like title and link.
```javascript
import React from 'react';
import { createRoot } from 'react-dom/client';
import { Helmet, HelmetProvider } from 'react-helmet-async';
const app = (
Hello World
Hello World
);
createRoot(document.getElementById('app')).render(app);
```
--------------------------------
### `defer` — Synchronous vs Deferred DOM Updates
Source: https://context7.com/staylor/react-helmet-async/llms.txt
Manages how DOM updates are applied. By default, `defer={true}` batches updates using `requestAnimationFrame` to prevent layout thrash. Setting `defer={false}` enforces synchronous updates, which is necessary for server-side rendering and recommended for testing environments.
```APIDOC
## `defer` — Synchronous vs Deferred DOM Updates
By default `defer={true}` batches DOM updates using `requestAnimationFrame` to avoid layout thrash. Set `defer={false}` for synchronous updates, which is required during server-side rendering and is recommended in tests.
### Usage
#### Synchronous Updates (SSR and Tests)
```tsx
import { Helmet, HelmetProvider } from 'react-helmet-async';
function SyncPage() {
return (
Sync Update
);
}
// Testing pattern — disable defer globally
import { Helmet } from 'react-helmet-async';
Helmet.defaultProps.defer = false; // at top of test file
```
#### Deferred Updates (Default for Client Rendering)
```tsx
import { Helmet, HelmetProvider } from 'react-helmet-async';
function DeferredPage() {
return (
{/* defer={true} by default */}
Deferred Update
);
}
```
### Parameters
- **defer** (boolean) - Set to `false` for synchronous DOM updates. Defaults to `true` for deferred updates using `requestAnimationFrame`.
```
--------------------------------
### SSR with toString() for Express/Node Servers
Source: https://context7.com/staylor/react-helmet-async/llms.txt
Use the `toString()` method for injecting head tags into HTML strings in traditional Node.js or Express server environments. Ensure `HelmetProvider` is used during rendering to populate the context.
```tsx
import { renderToString } from 'react-dom/server';
import React from 'react';
import { Helmet, HelmetProvider } from 'react-helmet-async';
// --- toString() approach (Express / raw Node server) ---
const helmetContext: { helmet?: any } = {};
const appHtml = renderToString(
My Page
`;
```
--------------------------------
### Server-Side Helmet Usage with HelmetProvider and Context
Source: https://github.com/staylor/react-helmet-async/blob/main/README.md
For server-side rendering, pass a context object to HelmetProvider. This context will capture the helmet state for the current request, which can then be accessed after rendering.
```javascript
import React from 'react';
import { renderToString } from 'react-dom/server';
import { Helmet, HelmetProvider } from 'react-helmet-async';
const helmetContext = {};
const app = (
Hello World
Hello World
);
const html = renderToString(app);
const { helmet } = helmetContext;
// helmet.title.toString() etc…
```
--------------------------------
### Manage Head Tags with Imperative Props API
Source: https://context7.com/staylor/react-helmet-async/llms.txt
Use the `` component with imperative props to set title, meta, link, script, and style tags. Array-type tags accept arrays of attribute objects, while object-type tags accept a single attribute map. Ensure HelmetProvider is used at the root.
```tsx
import { Helmet, HelmetProvider } from 'react-helmet-async';
function ArticlePage({ article }) {
return (
{article.content}
);
}
// Expected DOM output (React 16–18):
// My Article | My Blog
//
//
//
```
--------------------------------
### Manage DOM Updates with defer
Source: https://context7.com/staylor/react-helmet-async/llms.txt
Control DOM update behavior using `defer`. `defer={true}` (default) batches updates with `requestAnimationFrame` to prevent layout thrash. `defer={false}` forces synchronous updates, required for SSR and tests.
```tsx
import { Helmet, HelmetProvider } from 'react-helmet-async';
// Synchronous update — required for SSR and tests
function SyncPage() {
return (
Sync Update
);
}
// Testing pattern — disable defer globally
import { Helmet } from 'react-helmet-async';
Helmet.defaultProps.defer = false; // at top of test file
// Deferred update (default) — recommended for production client rendering
function DeferredPage() {
return (
{/* defer={true} by default */}
Deferred Update
);
}
```
--------------------------------
### Server-Side Rendering with Streaming
Source: https://github.com/staylor/react-helmet-async/blob/main/README.md
Use this snippet for server-side rendering with streaming. It requires manual context extraction for helmet data when not using React 19's renderToReadableStream.
```javascript
import through from 'through';
import { renderToNodeStream } from 'react-dom/server';
import { getDataFromTree } from 'react-apollo';
import { Helmet, HelmetProvider } from 'react-helmet-async';
import template from 'server/template';
const helmetContext = {};
const app = (
Hello World
Hello World
);
await getDataFromTree(app);
const [header, footer] = template({
helmet: helmetContext.helmet,
});
res.status(200);
res.write(header);
renderToNodeStream(app)
.pipe(
through(
function write(data) {
this.queue(data);
},
function end() {
this.queue(footer);
this.queue(null);
}
)
)
.pipe(res);
```
--------------------------------
### Dynamic Page Titles with titleTemplate
Source: https://context7.com/staylor/react-helmet-async/llms.txt
Set dynamic page titles using `title` and `titleTemplate`. `titleTemplate` applies a site-wide pattern with `%s` as a placeholder. `defaultTitle` is used when `title` is absent. The deepest `` with a non-empty title takes precedence.
```tsx
import { Helmet, HelmetProvider } from 'react-helmet-async';
// Layout component sets the global template
function Layout({ children }) {
return (
{children}
);
}
// Page component sets the page-specific title
function AboutPage() {
return (
<>
{/* document.title === "My Site — About Us" */}
About Us
>
);
}
// Empty title falls back to defaultTitle
function HomePage() {
return (
<>
{/* document.title === "My Site" */}
Welcome
>
);
}
// Declarative style with template expressions
function DynamicPage({ count }) {
return (
{`${count}`}
{/* document.title === "Dashboard (42 items) | Admin" */}
);
}
```
--------------------------------
### Prioritize SEO Tags in Helmet
Source: https://github.com/staylor/react-helmet-async/blob/main/README.md
Use the `prioritizeSeoTags` flag on a Helmet component to ensure specific SEO tags are rendered earlier in the head. This requires specific template rendering logic.
```javascript
A fancy webpage
```
```html
${helmet.title.toString()}
${helmet.priority.toString()}
${helmet.meta.toString()}
${helmet.link.toString()}
${helmet.script.toString()}
...
```
```html
A fancy webpage
...
```
--------------------------------
### `onChangeClientState` — DOM Change Callback
Source: https://context7.com/staylor/react-helmet-async/llms.txt
A callback function that is executed every time the client-side head state is updated. It receives the new aggregated state, as well as the tags that were added and removed from the DOM during that update cycle. This is useful for analytics, debugging, or integrating with third-party tag managers.
```APIDOC
## `onChangeClientState` — DOM Change Callback
A callback fired on every client-side head update, receiving the new aggregated state and the sets of tags added and removed from the DOM in that cycle. Useful for analytics, debugging, or driving third-party tag managers.
### Usage
```tsx
import { Helmet, HelmetProvider } from 'react-helmet-async';
import type { StateUpdate, HelmetTags } from 'react-helmet-async';
function TrackedPage() {
const handleHeadChange = (
newState: StateUpdate,
addedTags: HelmetTags,
removedTags: HelmetTags
) => {
if (addedTags.metaTags?.length) {
console.log('Meta tags added:', addedTags.metaTags.map(t => t.outerHTML));
}
if (removedTags.linkTags?.length) {
console.log('Link tags removed:', removedTags.linkTags.map(t => t.outerHTML));
}
// newState contains the full merged state:
// newState.title, newState.metaTags, newState.linkTags, etc.
window.dataLayer?.push({ event: 'helmetUpdate', title: newState.title });
};
return (
Tracked Page
);
}
// Callback receives:
// addedTags: { metaTags: [HTMLMetaElement], linkTags: [HTMLLinkElement] }
// removedTags: {} (nothing removed on first render)
```
### Parameters
- **newState** (StateUpdate) - The new aggregated state of the document head.
- **addedTags** (HelmetTags) - An object containing arrays of tags that were added to the DOM.
- **removedTags** (HelmetTags) - An object containing arrays of tags that were removed from the DOM.
```
--------------------------------
### Declarative JSX API for Head Tag Management
Source: https://context7.com/staylor/react-helmet-async/llms.txt
Accepts standard HTML head elements as JSX children, which are parsed and applied to the document head. Deeper components override shallower ones for the same tag key. Supports title, base, meta, link, script, style, noscript, base, html, and body tags.
```tsx
import { Helmet, HelmetProvider } from 'react-helmet-async';
function ProductPage({ product }) {
return (
{/* Outer Helmet sets site-wide defaults */}
{/* Inner Helmet overrides for this specific page */}
{product.name} — My Store
{product.name}
);
}
```
--------------------------------
### Prioritize SEO Tags in SSR
Source: https://context7.com/staylor/react-helmet-async/llms.txt
When `prioritizeSeoTags` is enabled, high-value SEO tags are moved to `helmet.priority` for SSR. Render `helmet.priority.toString()` immediately after `helmet.title` to front-load these tags in the ``.
```tsx
import { Helmet } from 'react-helmet-async';
function SEOPage() {
return (
Best Running Shoes 2024
{/* non-priority */}
{/* priority */}
{/* priority */}
{/* priority */}
{/* priority */}
{/* non-priority */}
);
}
```
```tsx
import { renderToString } from 'react-dom/server';
import { HelmetProvider } from 'react-helmet-async';
const helmetContext: { helmet?: any } = {};
renderToString();
const { helmet } = helmetContext;
const head = `
${helmet.title.toString()}
${helmet.priority.toString()}
${helmet.meta.toString()}
${helmet.link.toString()}
`;
```
--------------------------------
### Jest SSR Emulation
Source: https://github.com/staylor/react-helmet-async/blob/main/README.md
Configure Jest for server-side rendering emulation by setting `HelmetProvider.canUseDOM` to false. This is relevant for React versions 16-18.
```javascript
import { HelmetProvider } from 'react-helmet-async';
HelmetProvider.canUseDOM = false;
```
--------------------------------
### Context-Free Helmet Usage with HelmetData
Source: https://context7.com/staylor/react-helmet-async/llms.txt
Use `HelmetData` to manage Helmet state without a ``. Pass a stateful instance directly via the `helmetData` prop. This is useful for micro-frontends or isolated renders where a Provider is not feasible. Note: The `helmetData` prop is ignored in React 19.
```tsx
import { renderToString } from 'react-dom/server';
import { Helmet, HelmetData } from 'react-helmet-async';
// Standalone SSR render without HelmetProvider
const helmetData = new HelmetData({});
const html = renderToString(
);
// sharedHelmetData.context.helmet.base.toString()
// => ''
```
--------------------------------
### Helmet Usage Without Context
Source: https://github.com/staylor/react-helmet-async/blob/main/README.md
Instantiate `HelmetData` manually and pass it to the `` component when not using `HelmetProvider` context. This method is ignored in React 19.
```javascript
import React from 'react';
import { renderToString } from 'react-dom/server';
import { Helmet, HelmetData } from 'react-helmet-async';
const helmetData = new HelmetData({});
const app = (
Hello World
Hello World
);
const html = renderToString(app);
const { helmet } = helmetData.context;
```
--------------------------------
### Control HTML Encoding with encodeSpecialCharacters
Source: https://context7.com/staylor/react-helmet-async/llms.txt
Set `encodeSpecialCharacters={false}` to prevent HTML encoding of special characters in tag content. This is necessary for raw JSON-LD scripts or pre-encoded content. The default is `true`.
```tsx
import { Helmet, HelmetProvider } from 'react-helmet-async';
function StructuredDataPage() {
const structuredData = {
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: [
{
'@type': 'Question',
name: 'What is React Helmet Async?',
acceptedAnswer: {
'@type': 'Answer',
text: 'A thread-safe document manager for React.',
},
},
],
};
return (
{/* encodeSpecialCharacters=false required for raw JSON-LD — default true would mangle < > & */}
{/* Default encoding (true) — safe for regular meta content */}
{/* Rendered as: content="Page with "quotes" & ampersands" */}
);
}
```
--------------------------------
### `encodeSpecialCharacters` — HTML Encoding Control
Source: https://context7.com/staylor/react-helmet-async/llms.txt
Controls whether special characters in tag content are HTML-encoded. By default, characters like `&`, `<`, `>`, `
```APIDOC
## `encodeSpecialCharacters` — HTML Encoding Control
By default, special characters in tag content are HTML-encoded (`&`, `<`, `>`, `"`, `'`). Set `encodeSpecialCharacters={false}` to pass raw values through, needed for inline JSON-LD scripts or pre-encoded content.
### Usage
```tsx
import { Helmet, HelmetProvider } from 'react-helmet-async';
function StructuredDataPage() {
const structuredData = {
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: [
{
'@type': 'Question',
name: 'What is React Helmet Async?',
acceptedAnswer: {
'@type': 'Answer',
text: 'A thread-safe document manager for React.',
},
},
],
};
return (
{/* encodeSpecialCharacters=false required for raw JSON-LD — default true would mangle < > & */}
{/* Default encoding (true) — safe for regular meta content */}
{/* Rendered as: content="Page with "quotes" & ampersands" */}
);
}
```
### Parameters
- **encodeSpecialCharacters** (boolean) - Set to `false` to disable HTML encoding of special characters in tag content. Defaults to `true`.
```
=== COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.