Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

localStorage SecurityError during script init prevents customElements.define for all FluentUI elements #4761

Copy link
Copy link

Description

@DonRule
Issue body actions

When a page is loaded under a browser configuration that throws SecurityError on localStorage access (Edge/Chromium "Tracking Prevention" classifying the site as a tracker is the most common case), the FluentUI Blazor web-component bundle fails its initialization and none of the customElements.define('fluent-*', ...) calls execute. Every Fluent component on the page renders as an unknown HTML element — no styling, no interactivity, no shadow DOM. The page is effectively broken, with no recoverable error visible to the user.

PR #1157 added a localStorage availability check inside FluentDesignTheme, but the broader script-bundle init path that calls customElements.define is still wrapped (or transitively invoked) inside the same try chain, so a thrown SecurityError skips the registrations.

Repro

  1. Run any FluentUI Blazor app on a public domain (the issue does not repro on localhost, since browsers exempt localhost from tracking-prevention heuristics). Staging/production hostnames work for repro.

  2. Open the site in Microsoft Edge with Tracking prevention set to Strict, or in any browser configured to block third-party / cross-site cookies and storage on the test domain.

  3. Load any page that uses any Fluent component, e.g.:

    @page "/repro"
    @rendermode InteractiveServer
    
    <FluentTabs>
        <FluentTab Label="Tab A">A</FluentTab>
        <FluentTab Label="Tab B">B</FluentTab>
    </FluentTabs>
    <FluentButton Appearance="Appearance.Accent">Test</FluentButton>
  4. Open DevTools → Console. Observe the message "Tracking Prevention blocked access to storage for <URL>" appearing during script load.

  5. In the console, run:

    ['fluent-tabs','fluent-button','fluent-data-grid'].forEach(n =>
        console.log(n, customElements.get(n) ? 'defined' : 'NOT DEFINED'))

    All three return NOT DEFINED.

Expected behaviour

The FluentUI script should treat localStorage access failure as non-fatal — if the storage call throws, fall back to in-memory state for theme persistence (or skip persistence entirely) and continue to register the custom elements. A site without theme persistence is degraded; a site without any registered custom elements is broken.

Actual behaviour

A single SecurityError from localStorage.getItem(...) short-circuits the entire init path. customElements.define is never called, so every Fluent component renders as an unknown HTML element. There is no error in the Blazor circuit logs, no exception surfaced in the UI, and customElements.get('fluent-tabs') returns undefined indefinitely.

Workaround we currently apply

We inject the following script in the document head before blazor.web.js loads. It detects the storage block and substitutes an in-memory polyfill so subsequent localStorage calls succeed:

<script>
(function () {
    try { localStorage.getItem('_test'); }
    catch (e) {
        var _mem = {};
        Object.defineProperty(window, 'localStorage', {
            configurable: true,
            value: {
                getItem:    function (k) { return Object.prototype.hasOwnProperty.call(_mem, k) ? _mem[k] : null; },
                setItem:    function (k, v) { _mem[k] = String(v); },
                removeItem: function (k) { delete _mem[k]; },
                clear:      function ()  { _mem = {}; },
                key:        function (i) { return Object.keys(_mem)[i] || null; },
                get length() { return Object.keys(_mem).length; }
            }
        });
    }
})();
</script>

After installing this polyfill, all FluentUI custom elements register normally and the site works.

Why a library-level fix matters

Apps cannot reasonably know which of their hosting domains will be flagged by Edge tracking prevention — the classification is heuristic, opaque, and varies per user browsing history. The default FluentUI behaviour today is "if storage is blocked, the entire library silently fails to register". A try { localStorage.setItem(THEME_KEY, ...) } catch (e) { /* fall back to memory */ } around the theme persistence calls in the bundle would prevent this and restore graceful degradation.

Environment

  • FluentUI Blazor: 4.13.x — 4.14.1 (issue persists; PR [FluentDesignTheme] Check if LocalStorage is available #1157 only patched the FluentDesignTheme component, not the script-bundle init path)
  • .NET: 9.0
  • Hosting: Azure App Service (Windows), Blazor Web App with @rendermode InteractiveServer
  • Browser: Microsoft Edge with Tracking Prevention = Strict (Chromium-based browsers with "block third-party cookies and other site data" produce equivalent behaviour)
  • Domain pattern: any public hostname classified by Edge as a potential tracker. The same build works fine on localhost.
Reactions are currently unavailable

Metadata

Metadata

Labels

bugA bugA bugstatus:in-progressWork is in progressWork is in progressv5For the next major versionFor the next major version

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions

Morty Proxy This is a proxified and sanitized view of the page, visit original site.