Symbol with Content Input causes hydration errors in Next.js

Builder content link

Builder public api key
7665eaf231524f07922360adfeffa153

Detailed steps to reproduce the bug
I did a minimal setup to reproduce this error:

  1. Create a blank page.
  2. Create a Symbol “Simple Text Section” that receives a Content Input field dynamicText and displays it on the screen using data biding.
  3. Add the Symbol to the blank page and publish it.
  4. By accessing the page in localhost:3000/blank, I’m getting hydration errors like:
Prop `dangerouslySetInnerHTML` did not match. Server: "" Client: "This is the text being passed from the blank page to symbol's content input" Error 

I noticed that this is happening when we have data being bound. Either from the “Content Input”, or using the “Connect Data”. Every time we bound some data to a symbol, it causes hydration errors.

Screenshots or video link



Code stack you are integrating Builder with
NextJS

Reproducible code example
This is my app/[[...page]]/page.tsx setup:

import { builder } from '@builder.io/sdk';
import { RenderBuilderContent } from '../../components/builder';

// Builder Public API Key set in .env file
builder.init(process.env.NEXT_PUBLIC_BUILDER_API_KEY!);

interface PageProps {
  params: {
    page: string[];
  };
}

export default async function Page(props: PageProps) {
  const builderModelName = 'page';

  const content = await builder
    // Get the page content from Builder with the specified options
    .get(builderModelName, {
      userAttributes: {
        // Use the page path specified in the URL to fetch the content
        urlPath: '/' + (props?.params?.page?.join('/') || ''),
      },
      cachebust: true /** @todo check if we need this in production */,
      options: {
        // Enrich the content with the data of the referenced models
        // (e.g. the data of the referenced model "section" will be included in the response)
        enrich: true,
      },
    })
    .toPromise();

  console.log(JSON.stringify(content, null, 2));

  return (
    <>
      {/* Render the Builder page */}
      <RenderBuilderContent  content={content} model={builderModelName} />
    </>
  );
}

And this is the RenderBuilderContent component:

'use client';
import { ComponentProps } from 'react';
import { BuilderComponent, useIsPreviewing } from '@builder.io/react';
import { builder } from '@builder.io/sdk';
import DefaultErrorPage from 'next/error';
import '../builder-registry';
import { builderContext } from '@/builder-context';

type BuilderPageProps = ComponentProps<typeof BuilderComponent>;

// Builder Public API Key set in .env file
builder.init(process.env.NEXT_PUBLIC_BUILDER_API_KEY!);

export function RenderBuilderContent({
  options,
  content,
  model,
}: BuilderPageProps) {
  // Call the useIsPreviewing hook to determine if
  // the page is being previewed in Builder
  const isPreviewing = useIsPreviewing();
  // If "content" has a value or the page is being previewed in Builder,
  // render the BuilderComponent with the specified content and model props.
  if (content || isPreviewing) {
    return (
      <BuilderComponent
        context={builderContext}
        options={options}
        content={content}
        model={model}
      />
    );
  }
  // If the "content" is falsy and the page is
  // not being previewed in Builder, render the
  // DefaultErrorPage with a 404.
  return <DefaultErrorPage statusCode={404} />;
}

Hello @c-eustaquio,

Welcome to the Builder.io forum!

We attempted to reproduce the issue on our end but were unsuccessful. Could you please confirm the versions of Next.js and the Builder React SDK you are using? This information will help us investigate further.

Thank you!

Hello, I’m experiencing the same situation in Remix.

Using: "@builder.io/react": "^7.0.1"

This is one of the hydration diffs, the rest are the same, with different inner HTML:

                    <span
                      className="builder-text css-1qggkls"
                      dangerouslySetInnerHTML={{
+                       __html: "<h1>Photography</h1>"
-                       __html: ""
                      }}
                      ref={function ref}
                    >

The content API is returning both the symbol and the associated data from its inputs. Given this, I’d argue <BuilderComponent> is not replacing the __html for text input fields on the server.

Until we wait for a solution, I think the Rich text / HTML input does work well during SSR.

Hello @oscar,

For remix app integration, we recommend using our GEN 2 SDK, for reference and examples, you can refer to the below links

1 Like

Hello Manish,

I’ve already gone back and forth between React SDKs, and the Gen 2 SDK for React performs poorly.

When I profiled my application with it, the main thread on the browser blocked for more than five seconds on the same task, whereas the Gen 1 SDK, which is built on actual React code and not extruded through Mitosis, splits the tasks and exploits concurrency effectively.

Additionally, I’m not sure why you’re recommending this, since the engineering team is clearly aware of such issues, and claim it’s not recommended for production:

Going back to the topic - we agree this seems to be an issue on the SDK side of things, as @c-eustaquio and I are using two different React meta-frameworks, but the same SDK generation.

I’m using the latest available version of the SDK, 7.0.1. Anything else that might be helpful for the team to investigate, feel free let me know.

Hi! @manish-sharma

Here are the versions of my dependencies:

  "dependencies": {
    "@builder.io/dev-tools": "^1.1.24",
    "@builder.io/react": "^5.0.6",
    "@builder.io/sdk": "^3.0.3",
    "next": "14.2.15",
    "react": "^18",
    "react-dom": "^18"
  }

Hello @c-eustaquio,

We are aware of the hydration issue when using Remix with our GEN 1 SDK. We are investigating this issue further and we will provide you with an update as soon as we make progress.

Best regards,

Hi @manish-sharma just to clarify: The issue I’m seeing is not with Remix. My project is in Next.js. There is where I’m getting hydration errors.

Hello @c-eustaquio,

Could you confirm if you are using NextJs 15? If not, you can use our hydration overlay plugin which might help address the hydration issue

I’m using Nextjs 14.2.15 - I tried using the hydration overlay but without success

Hi @c-eustaquio,

I was able to reproduce the issue on my end, and it appears to be related to a crash with the isolate-vm package. I resolved the error by adding the NODE_OPTIONS=--no-node-snapshot configuration to the Node process.

Here’s an example of how to update your package.json scripts:

  "scripts": {
    "dev": "NODE_OPTIONS=--no-node-snapshot next dev",
    "build": "NODE_OPTIONS=--no-node-snapshot next build",
    "start": "NODE_OPTIONS=--no-node-snapshot next start",
    "lint": "next lint"
  },

Could you try this solution and let us know if it resolves the issue on your end?

Thanks,