Skip to content

Erreur dans la console lors de l'utilisation de la lib #442

Description

@Viczei

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.

Activity

  1. self-assigned this
    on Aug 11, 2025
  2. garronej commented on Dec 9, 2025

    @garronej
    Collaborator

    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)

  3. kevbarns commented on Sep 2, 2026

    @kevbarns
    Collaborator

    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énements SecurityError: 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 :

    const safeLocalStorage = {
        getItem: (key: string): string | null => {
            try {
                return localStorage.getItem(key);
            } catch {
                return null;
            }
        },
        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.

  4. added theissue type on Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions