react-helmet-async

repository·main·Indexed 25 days ago

https://github.com/staylor/react-helmet-async

A thread-safe fork of react-helmet for React 16–18 with native support for React 19+. It enables management of document metadata such as <title>, <meta>, and <link> tags for both client-side rendering and asynchronous server-side rendering (SSR). Version 3.0.0 leverages React 19's native metadata hoisting, while maintaining legacy behavior for older versions via HelmetProvider and HelmetData.

Tokens
4.6K
Snippets
8
Records
18
Agent score
80%

What's inside react-helmet-async

  1. How react-helmet-async behaves with React 19

    main

    Starting with version 3.0.0, the package detects React 19 at runtime and changes its behavior to leverage React's native metadata hoisting:

    • React 19+: <Helmet> renders actual DOM elements, and React handles hoisting them to <head>. <HelmetProvider> becomes a transparent passthrough.

      • Note: htmlAttributes and bodyAttributes are still applied via direct DOM manipulation.
      • Note: The context object will not be populated with helmet state on React 19. If you rely on context for SSR, render tags directly in your component tree instead.
      • Note: The prioritizeSeoTags flag and helmetData prop are ignored.
    • React 16–18: The existing behavior is preserved where <Helmet> collects tags, deduplicates them, and applies them via manual DOM manipulation (client) or serialization (server).

  2. Extract Helmet state during Server-Side Rendering (SSR)

    main

    For React versions 16–18, instead of using static methods like .rewind(), you must pass a context object to the HelmetProvider. This object will be populated with the helmet state specific to that request after rendering.

    import React from 'react';
    import { renderToString } from 'react-dom/server';
    import { Helmet, HelmetProvider } from 'react-helmet-async';
    
    const helmetContext = {};
    
    const app = (
      <HelmetProvider context={helmetContext}>
        <App>
          <Helmet>
            <title>Hello World</title>
            <link rel="canonical" href="https://www.tacobell.com/" />
          </Helmet>
          <h1>Hello World</h1>
        </App>
      </HelmetProvider>
    );
    
    const html = renderToString(app);
    
    const { helmet } = helmetContext;
    
    // helmet.title.toString() etc…
  3. Prioritize SEO tags for specific head ordering

    main

    In React 16–18, you can use the prioritizeSeoTags prop on a <Helmet> component to ensure certain tags appear earlier in the <head>. Tags within a prioritized <Helmet> are separated from standard tags in the helmetContext object, allowing you to render them specifically in your server template.

    Note for React 19: This flag has no effect, as tag order is determined by React's rendering order.

    // In the component:
    <Helmet prioritizeSeoTags>
      <title>A fancy webpage</title>
      <link rel="notImportant" href="https://www.chipotle.com" />
      <meta name="whatever" value="notImportant" />
      <link rel="canonical" href="https://www.tacobell.com" />
      <meta property="og:title" content="A very important title"/>
    </Helmet>
    
    // In your server template:
    <html>
      <head>
        ${helmet.title.toString()}
        ${helmet.priority.toString()}
        ${helmet.meta.toString()}
        ${helmet.link.toString()}
        ${helmet.script.toString()}
      </head>
      ...
    </html>
  4. Use Helmet without Context

    main

    You can bypass the HelmetProvider by manually creating a HelmetData instance and passing it to the Helmet component via the helmetData prop. This is useful for specific edge cases where a provider is not available.

    Note for React 19: The helmetData prop is ignored on React 19.

    import React from 'react';
    import { renderToString } from 'react-dom/server';
    import { Helmet, HelmetData } from 'react-helmet-async';
    
    const helmetData = new HelmetData({});
    
    const app = (
        <App>
          <Helmet helmetData={helmetData}>
            <title>Hello World</title>
            <link rel="canonical" href="https://www.tacobell.com/" />
          </Helmet>
          <h1>Hello World</h1>
        </App>
    );
    
    const html = renderToString(app);
    
    const { helmet } = helmetData.context;
  5. How to use react-helmet-async with Streams

    main

    This package works with streaming if your <head> data is output outside of renderToNodeStream(). This typically requires a hydration method that parses the React tree (like getDataFromTree) before starting the stream.

    Note for React 19: React 19's renderToReadableStream natively handles <title>, <meta>, and <link> hoisting during streaming, so manual context extraction is not necessary.

    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 = (
      <HelmetProvider context={helmetContext}>
        <App>
          <Helmet>
            <title>Hello World</title>
            <link rel="canonical" href="https://www.tacobell.com/" />
          </Helmet>
          <h1>Hello World</h1>
        </App>
      </HelmetProvider>
    );
    
    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);
  6. Install and use react-helmet-async in a React application

    main

    To use react-helmet-async, you must wrap your application in a HelmetProvider. This encapsulates the Helmet state for your React tree, making it thread-safe for server-side rendering. Note that since version 1.0.0, the package uses named exports: import { Helmet, HelmetProvider } from 'react-helmet-async'.

    import React from 'react';
    import { createRoot } from 'react-dom/client';
    import { Helmet, HelmetProvider } from 'react-helmet-async';
    
    const app = (
      <HelmetProvider>
        <App>
          <Helmet>
            <title>Hello World</title>
            <link rel="canonical" href="https://www.tacobell.com/" />
          </Helmet>
          <h1>Hello World</h1>
        </App>
      </HelmetProvider>
    );
    
    createRoot(document.getElementById('app')).render(app);
  7. Prioritize SEO tags for better search engine visibility

    main

    When prioritizeSeoTags is set to true in the mapStateOnServer options, the library uses an internal prioritizer to reorder metaTags, linkTags, and scriptTags.

    This ensures that critical SEO tags (defined by SEO_PRIORITY_TAGS) are placed at the beginning of their respective groups. The resulting priority object in the returned state contains toComponent() and toString() methods that specifically handle these prioritized tags.

  8. Supported tags in Helmet

    main

    The Helmet component supports specific HTML tags. Some tags are treated as single objects (like <title>, <html>, and <body>), while others are treated as arrays of elements (allowing multiple instances of the same tag type).

    Array-type tags (Multiple instances allowed)

    • <link />
    • <meta />
    • <noscript />
    • <script />
    • <style />

    Object-type tags (Single instance/attributes)

    • <title /> (Supports titleAttributes via props)
    • <body> (Supports bodyAttributes via props)
    • <html> (Supports htmlAttributes via props)
    • Other standard tags (mapped to their respective attributes)

    Special Child Handling

    • <script /> and <noscript />: Children are mapped to innerHTML.
    • <style />: Children are mapped to cssText.
    • All other tags: Children must be strings (e.g., <title>My Title</title>).
  9. Configure HelmetProvider for Jest testing

    main

    When testing with Jest and needing to emulate Server-Side Rendering (SSR) for React 16–18, you must set HelmetProvider.canUseDOM = false to ensure the library behaves as expected in a non-browser environment.

    Note for React 19: This setting has no effect on React 19 as HelmetProvider is a passthrough.

    import { HelmetProvider } from 'react-helmet-async';
    
    HelmetProvider.canUseDOM = false;
  10. Map helmet state on the server with mapStateOnServer

    main

    Use mapStateOnServer to transform the helmet state collected during server-side rendering into a format that can be easily rendered as React components or serialized into HTML strings. This is essential for SEO and ensuring that metadata (like <title>, <meta>, and <link> tags) is correctly included in the initial HTML sent to the client.

    Configuration Options

    The function accepts a MappedServerState object with the following properties:

    • title: The page title string.
    • titleAttributes: Attributes for the <title> tag.
    • baseTag: Configuration for the <base> tag.
    • htmlAttributes: Attributes for the <html> tag.
    • bodyAttributes: Attributes for the <body> tag.
    • linkTags: Array of link tags.
    • metaTags: Array of meta tags.
    • scriptTags: Array of script tags.
    • styleTags: Array of style tags.
    • noscriptTags: Array of noscript tags.
    • encode: Boolean (default true) to determine if special characters should be encoded in string output.
    • prioritizeSeoTags: Boolean. When true, it uses getPriorityMethods to reorder meta, link, and script tags based on SEO priority.

    Return Value

    The function returns an object where each key (e.g., meta, link, title, htmlAttributes) contains an object with two methods:

    1. toComponent(): Returns an array of React.ReactElements.
    2. toString(): Returns the serialized HTML string.
  11. Use HelmetProvider to manage head tags

    main

    The HelmetProvider component is used to encapsulate the state of head tags (like <title>, <meta>, etc.) for a component tree. It provides the necessary context for Helmet components to update the document head.

    React 19+ Behavior

    In React 19 and later, React handles <head> element hoisting natively. Consequently, HelmetProvider acts as a simple passthrough and does not perform any internal bookkeeping.

    Legacy React Behavior

    In versions prior to React 19, HelmetProvider initializes HelmetData to manage the state of head tags and provides it via a context provider to the component tree.

    Server-Side Rendering (SSR) Configuration

    You can pass an initial state to the provider via the context prop. This is useful for hydrating the head state from the server. The context object can contain a helmet property of type HelmetServerState or null.