react-dsfr icon indicating copy to clipboard operation
react-dsfr copied to clipboard

`Extra attributes from the server: data-fr-js-modal-button`

Open arnaudambro opened this issue 1 year ago • 16 comments

Hello

I've this warning using react-dsfr in my Remix project (here: https://github.com/betagouv/zacharie/tree/24f0594140d20aa8d93f271947c8dd62fdb83112)

I have no clue how to try and fix it...

Warning: Extra attributes from the server: data-fr-js-modal-button
    at button
    at http://localhost:3232/node_modules/.vite/deps/chunk-EIDWZ6ND.js?v=628cc138:41:15
    at fr-theme-modal-modal
    at Display (http://localhost:3232/node_modules/.vite/deps/@codegouvfr_react-dsfr_Header.js?v=628cc138:426:17)
    at http://localhost:3232/node_modules/.vite/deps/@codegouvfr_react-dsfr_Header.js?v=628cc138:752:11
    at TableauDeBordLayout (http://localhost:3232/app/routes/tableau-de-bord.tsx:9:18)
    at RenderedRoute (http://localhost:3232/node_modules/.vite/deps/chunk-7GTNRECA.js?v=628cc138:401:5)
    at Outlet (http://localhost:3232/node_modules/.vite/deps/chunk-7GTNRECA.js?v=628cc138:739:26)
    at HoneypotProvider (http://localhost:3232/node_modules/.vite/deps/remix-utils_honeypot_react.js?v=628cc138:27:29)
    at App (http://localhost:3232/app/root.tsx:199:7)
    at body
    at html
    at Layout (http://localhost:3232/app/root.tsx:31:3)
    at RenderedRoute (http://localhost:3232/node_modules/.vite/deps/chunk-7GTNRECA.js?v=628cc138:401:5)
    at RenderErrorBoundary (http://localhost:3232/node_modules/.vite/deps/chunk-7GTNRECA.js?v=628cc138:361:5)
    at DataRoutes (http://localhost:3232/node_modules/.vite/deps/chunk-7GTNRECA.js?v=628cc138:1394:5)
    at Router (http://localhost:3232/node_modules/.vite/deps/chunk-7GTNRECA.js?v=628cc138:746:15)
    at RouterProvider (http://localhost:3232/node_modules/.vite/deps/chunk-7GTNRECA.js?v=628cc138:1209:5)
    at RemixErrorBoundary (http://localhost:3232/node_modules/.vite/deps/chunk-7GTNRECA.js?v=628cc138:2757:5)
    at RemixBrowser (http://localhost:3232/node_modules/.vite/deps/chunk-7GTNRECA.js?v=628cc138:4294:46)

arnaudambro avatar Sep 12 '24 07:09 arnaudambro

Hello @arnaudambro,

Assuming you're using the components exposed by react-dsfr, this error is very strange.

This attribute is added dynamically by the JavaScript code of @gouvfr/dsfr. This code isn't loaded on the backend during SSR. It cannot possibly be. If it was many errors would be thrown.

If you can produce a reproduction repo with precise steps to reproduce I'll be able to debug.

garronej avatar Sep 12 '24 08:09 garronej

If you can produce a reproduction repo with precise steps to reproduce I'll be able to debug.

this is the repo I'm working on, with the code as is https://github.com/betagouv/zacharie/tree/24f0594140d20aa8d93f271947c8dd62fdb83112

the file your might be interested in is ./app/entry.client.tsx I think

arnaudambro avatar Sep 12 '24 08:09 arnaudambro

Please provide the exact commands to reproduce and where I should navigate to reproduce the error.

garronej avatar Sep 12 '24 08:09 garronej

git clone [email protected]:betagouv/zacharie.git
cd ./zacharie
git checkout 59b8832994911b2ce3523f8bee114048a6ddb8d2
yarn install
yarn dev-test-react-dsfr

this should work

arnaudambro avatar Sep 12 '24 08:09 arnaudambro

I'm not getting the error described:

image

garronej avatar Sep 12 '24 08:09 garronej

mmm yes, my bad, it's once you're logged in

then on the url http://localhost:3232/tableau-de-bord

if you remove everything except the header in ./app/tableau-de-bord.tsx you still get the error

import { Header } from "@codegouvfr/react-dsfr/Header";

export default function TableauDeBordLayout() {
  return (
    <>
      <Header
        brandTop={
          <>
            Ministère
            <br />
            de l'Agriculture
          </>
        }
        homeLinkProps={{
          href: "/",
          title: "Zacharie - Ministère de l'Agriculture",
        }}
        id="fr-header-header-with-quick-access-items"
        serviceTagline="La Fiche d’Examen Initial (FEI) simplifiée"
        serviceTitle="Zacharie"
      />
    </>
  );
}

I made a branch for this test: https://github.com/betagouv/zacharie/tree/test--warning-dsfr

arnaudambro avatar Sep 12 '24 09:09 arnaudambro

I still don't see the error you're refering to in this issue:

image image

garronej avatar Sep 12 '24 11:09 garronej

Hello, we're seeing similar warning in our project (only in dev mode) :

Screenshot from 2024-09-12 15-11-28

It can be reproduced on this PR : https://github.com/SocialGouv/code-du-travail-numerique/pull/6078

Run

yarn && yarn build
yarn dev:frontend

Then go to http://localhost:3000/mentions-legales

carolineBda avatar Sep 12 '24 13:09 carolineBda

Hello @carolineBda,

This is not the same error and not the same meta framwork. Please open a new issue.

garronej avatar Sep 12 '24 14:09 garronej

ok :+1:

carolineBda avatar Sep 12 '24 14:09 carolineBda

@carolineBda and unfortunatly, I can't reproduce either:

image

garronej avatar Sep 12 '24 14:09 garronej

I still don't see the error you're refering to in this issue:

are you sure you're on the branch ? https://github.com/betagouv/zacharie/tree/test--warning-dsfr cause the error shows you need a postgres db but in that branch I removed the dependency to this - and it works fine on my computer

arnaudambro avatar Sep 12 '24 18:09 arnaudambro

Yes. I was on the branch.

image

I'll try again after your update

garronej avatar Sep 12 '24 20:09 garronej

Still can reproduce, neither with chrome or firefox, neither with network throtling.

The error I'm getting is:

image

I can look at this but this isn't the same error you're refering to, it's related to Remix Link component.

Maybe produce a dump of the error with https://www.replay.io/ ?

garronej avatar Sep 12 '24 21:09 garronej

Maybe try clearing your browser cache as well.

image

It's maybe due to the fact that you've done this:

image

garronej avatar Sep 12 '24 21:09 garronej

still here...

sorry I have no time right now to dig in a little bit more, but in October/November I think I'll be able to

Thanks anyway, great job done there !

arnaudambro avatar Sep 19 '24 09:09 arnaudambro

This error appears when the lang attribute is set on the <DsfrProvider /> component and when using Next.js App router :

Here is a minimum layout to reproduce the error :

app/layout.tsx

import { type PropsWithChildren } from 'react';
import { DsfrProvider } from '@codegouvfr/react-dsfr/next-appdir/DsfrProvider';
import { getHtmlAttributes } from '@codegouvfr/react-dsfr/next-appdir/getHtmlAttributes';
import { StartDsfr } from '@/components/StartDsfr';

const RootLayout = ({ children }: PropsWithChildren) => {
  return (
    <html lang="fr" {...getHtmlAttributes({ defaultColorScheme: 'light', lang: 'fr' })}>
      <head>
        <StartDsfr />
      </head>
      <body>
        <DsfrProvider lang="fr">{children}</DsfrProvider>
      </body>
    </html>
  );
};

export default RootLayout;

For the <StartDsfr /> component see : https://react-dsfr.codegouv.studio/routing

lutangar avatar Jan 06 '25 14:01 lutangar

Hello @lutangar, I doubt that is the root cause of the issue.

Here again I can't reproduce, I tried with the Next App Router Starter.

I'm down to fix whatever as long as you can provide me a reproduction path.

PS: getHtmlAttributes already sets the lang property so having lang="fr" {...getHtmlAttributes({ lang: 'fr' })} is redundant.

garronej avatar Jan 08 '25 02:01 garronej

@garronej

I have such similar issue, but on my side it's an hydratation error between Server & Client.

Here is a reproduction of the problem https://github.com/mission-apprentissage/react-dsfr-next-appdir-demo/commit/971280055dd7c2f636aa14be305699075ec62b9d

That's a different error message, but I think it's all related to Suspense boundary

moroine avatar Mar 25 '25 08:03 moroine

Hello,

Support for Next.js 15 just landed

Updated documentation:
https://react-dsfr.codegouv.studio/#next-js-app-router

Updated starter project:
https://github.com/garronej/react-dsfr-next-appdir-demo

Unfortunately, I couldn’t make it work without introducing breaking changes.
Please refer to the following commit to see what you’ll need to update:
https://github.com/garronej/react-dsfr-next-appdir-demo/commit/aaabb7925823fb163b83ffd438da7264084b629b

garronej avatar Mar 26 '25 21:03 garronej

I had a build issue which is fixed with the latest relase, thanks!

But I'm still experiencing hydratation errors (https://github.com/mission-apprentissage/react-dsfr-next-appdir-demo)

@garronej what about creating Github release to add notes including potential breaking change ?

moroine avatar Mar 27 '25 08:03 moroine

Yes sorry @moroine the hydratation error is still present. I'm looking into it.

garronej avatar Mar 27 '25 09:03 garronej

Hello @moroine, @arnaudambro & @carolineBda,

I've made further updates to the Next App Router setup.
Please refer to the documentation here: https://react-dsfr.codegouv.studio/
The example setup (Next 15, React 19, using loading.tsx): https://github.com/garronej/react-dsfr-next-appdir-demo
The deployment of the example: https://react-dsfr-next-appdir-demo.vercel.app/


The Core Issue: Supporting SSR Streaming

The main challenge lies in how to support SSR streaming.
The @gouvfr/dsfr package was not designed with modern frameworks like Next.js in mind.

It relies on:

  • A single CSS stylesheet
  • A single JS module that is "started" when the DOM is fully ready

However, in a streaming SSR context, there’s no single point in time where the DOM is considered fully ready. Additional HTML chunks may be streamed later, as server components are progressively sent by the server.

This introduces a critical problem:

  • Before DSFR is started, components are non-interactive
  • After DSFR is started, any additional HTML streamed into the page may cause hydration errors, because DSFR will attempt to hydrate elements immediately as they appear in the DOM

There is no way within DSFR to:

  • Selectively hydrate parts of the DOM
  • Delay hydration until specific conditions are met

What This Means in Practice

As a result, I can’t abstract this logic away for you.
You must explicitly decide when the page is ready, and manually mount the component <StartDsfrOnHydration />.

Example usage:

src/app/page.tsx

import { StartDsfrOnHydration } from "../dsfr-bootstrap";

export default function Page() {
  return (
    <>
      {/* Important: You must mount this component on every page of your app */}
      <StartDsfrOnHydration />
      <h1>Welcome!</h1>
    </>
  );
}

Important to Understand:

  • Until <StartDsfrOnHydration /> is hydrated, DSFR elements remain non-interactive
  • Once it is hydrated, you can no longer stream in new HTML chunks conaining DSFR components (i.e. no server components below this point)

Your Options Moving Forward

You can choose between two strategies:

  1. Avoid SSR Streaming entirely — or only use it if you fully understand the implications and what will cause idration errors.
  2. Use DSFR components only for layout (e.g., header and footer), and rely on MUI components for the rest. Use <MuiDsfrProvider> to maintain visual consistency.

I'm sorry this isn't more seamless — but unfortunately, this is the current state of things.
We have very limited influence over DSFR's development. DSFR 2.0 is not being built in the open, and I strongly suspect these architectural constraints won't be addressed anytime soon.

Let me know if anything is unclear.

garronej avatar Mar 27 '25 14:03 garronej

@garronej what about creating GitHub releases to add notes, including potential breaking changes?

In my experience, very few people actually read release notes and we release too often.
Also, maintaining this project is already quite time consuming, and we've received zero support—past or present—from the SIG or DINUM.

That said, here’s what I can commit to:

  • Ensuring compatibility with the latest version of Next.js.
  • Keeping the documentation fully up to date.
  • Keeping the starter project updated: https://github.com/garronej/react-dsfr-next-appdir-demo
  • Avoiding silent breaking changes: if something breaks, it will trigger type errors.

Beyond that, I simply don't have the bandwidth to provide scheduled updates or detailed migration guides.

garronej avatar Mar 27 '25 14:03 garronej