You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Erreur dans la console lors de l'utilisation de la lib #442
Lorsque le site utilisant react-dsfr est utilisé à travers une iframe. Dans ce cas, Il arrive souvent que l'accès au localstorage soit interdit et l'erreur suivante remonte du react-dsfr :
SecurityError: Failed to read the 'localStorage' property from 'Window': Access is denied for this document.
Bonjour @garronej, le problème est toujours présent en 1.34.0 (les accès à localStorage dans src/useIsDark/client.ts ne sont pas protégés sur main). Voici des données de production pour aider à le qualifier.
Contexte
Sur La bonne alternance (Next.js 16 App Router, DsfrProvider de next-app-router), Sentry remonte depuis mars 2026 :
~870 événementsSecurityError: Failed to read the 'localStorage' property from 'Window': Access is denied for this document. (DOMException.code: 18)
et, avec le même trace_id, autant d'événements Error: react-dsfr not initialized. Refer to the documentation for setup instructions…
Le second est une conséquence directe du premier : start() plante avant d'initialiser $clientSideIsDark, puis le premier useIsDark() (ici via MuiDsfrThemeProvider) lève l'erreur « not initialized ». Le rendu client de la page est perdu pour ces visiteurs.
Navigateurs concernés sur 30 jours : quasi exclusivement Chromium (Chrome Mobile Android ~65 %, Edge, Chrome desktop). Aucun WebKit/Firefox, ce qui est cohérent : Chromium lève une SecurityError dès la lecture de window.localStorage quand le stockage est bloqué (iframe tierce avec cookies tiers bloqués, WebView avec stockage désactivé, politique d'entreprise), là où les autres navigateurs renvoient un objet inerte ou échouent seulement à l'écriture.
Stacktrace (1.33.0, minifié par Turbopack, chemins source résolus)
SecurityError: Failed to read the 'localStorage' property from 'Window': Access is denied for this document.
at startClientSideIsDarkLogic @codegouvfr/react-dsfr/src/useIsDark/client.ts:144 localStorage.getItem("scheme-website-config-default")
at start @codegouvfr/react-dsfr/src/start.ts:37
at DsfrProvider useMemo @codegouvfr/react-dsfr/src/next-app-router/DsfrProvider.tsx:74
Les autres accès non protégés dans le même fichier : lignes 93, 150, 152, 183 et 236 (getItem / setItem / removeItem).
Piste de correctif
Un petit wrapper qui avale la SecurityError et se comporte comme un stockage vide, utilisé partout dans useIsDark/client.ts :
constsafeLocalStorage={getItem: (key: string): string|null=>{try{returnlocalStorage.getItem(key);}catch{returnnull;}},setItem: (key: string,value: string): void=>{try{localStorage.setItem(key,value);}catch{// stockage indisponible : la préférence ne sera simplement pas persistée}},removeItem: (key: string): void=>{try{localStorage.removeItem(key);}catch{}}};
Avec ce comportement, getItem renvoie null et le code existant retombe naturellement sur colorSchemeExplicitlyProvidedAsParameter / prefers-color-scheme, sans changer la logique. Le même try/catch protégerait aussi le QuotaExceededError de Safari en navigation privée sur les anciennes versions.
Je peux ouvrir une PR dans ce sens si tu es d'accord avec l'approche.
Activity
garronej commentedon Dec 9, 2025
Hello @Viczei, do you still have the problem or did you find a workaround. (To know if it's worth it to tackle it now)
kevbarns commentedon Sep 2, 2026
Bonjour @garronej, le problème est toujours présent en
1.34.0(les accès àlocalStoragedanssrc/useIsDark/client.tsne sont pas protégés surmain). Voici des données de production pour aider à le qualifier.Contexte
Sur La bonne alternance (Next.js 16 App Router,
DsfrProviderdenext-app-router), Sentry remonte depuis mars 2026 :SecurityError: Failed to read the 'localStorage' property from 'Window': Access is denied for this document.(DOMException.code: 18)trace_id, autant d'événementsError: react-dsfr not initialized. Refer to the documentation for setup instructions…Le second est une conséquence directe du premier :
start()plante avant d'initialiser$clientSideIsDark, puis le premieruseIsDark()(ici viaMuiDsfrThemeProvider) lève l'erreur « not initialized ». Le rendu client de la page est perdu pour ces visiteurs.Navigateurs concernés sur 30 jours : quasi exclusivement Chromium (Chrome Mobile Android ~65 %, Edge, Chrome desktop). Aucun WebKit/Firefox, ce qui est cohérent : Chromium lève une
SecurityErrordès la lecture dewindow.localStoragequand le stockage est bloqué (iframe tierce avec cookies tiers bloqués, WebView avec stockage désactivé, politique d'entreprise), là où les autres navigateurs renvoient un objet inerte ou échouent seulement à l'écriture.Stacktrace (1.33.0, minifié par Turbopack, chemins source résolus)
Les autres accès non protégés dans le même fichier : lignes 93, 150, 152, 183 et 236 (
getItem/setItem/removeItem).Piste de correctif
Un petit wrapper qui avale la
SecurityErroret se comporte comme un stockage vide, utilisé partout dansuseIsDark/client.ts:Avec ce comportement,
getItemrenvoienullet le code existant retombe naturellement surcolorSchemeExplicitlyProvidedAsParameter/prefers-color-scheme, sans changer la logique. Le mêmetry/catchprotégerait aussi leQuotaExceededErrorde Safari en navigation privée sur les anciennes versions.Je peux ouvrir une PR dans ce sens si tu es d'accord avec l'approche.