Avatar
← Back To Blog
js-static-blazor.png

Using JavaScript With Static Rendered Blazor

User Avatar
YodasMyDad 9 days ago

In this blog post, we'll dive into how you can smoothly integrate JavaScript into your Blazor Web App, even when using static server-side rendering (static SSR) and enhanced navigation.

Why Static SSR and Enhanced Navigation?

When using static SSR, your page is rendered server-side, and with enhanced navigation, you can switch between pages without reloading everything.

The problem? Page-specific JavaScript won't run/fire when navigating between pages. But don’t worry, there is a simple solution for that.

Adding Highlight.js To This Blog

I stumbled on this issue when building this blog. I wanted to use the Block List Editor and use the Code Editor to display styled code output. I added the the highlight.js CDN link and then called hljs.highlightAll() on my page. When I refreshed the page, the script ran, however, when I navigated to the page the script didn't run, because of how Blazor enhanced navigation works.

To get around this, you need to add the Javascript file below in the root of your wwwroot in your Blazor RCL, making sure you follow the naming convention of

YourProjectName.lib.module.js

const pageScriptInfoBySrc = new Map();

function registerPageScriptElement(src) {
    if (!src) {
        throw new Error('Must provide a non-empty value for the "src" attribute.');
    }

    let pageScriptInfo = pageScriptInfoBySrc.get(src);

    if (pageScriptInfo) {
        pageScriptInfo.referenceCount++;
    } else {
        pageScriptInfo = {referenceCount: 1, module: null};
        pageScriptInfoBySrc.set(src, pageScriptInfo);
        initializePageScriptModule(src, pageScriptInfo);
    }
}

function unregisterPageScriptElement(src) {
    if (!src) {
        return;
    }

    const pageScriptInfo = pageScriptInfoBySrc.get(src);

    if (!pageScriptInfo) {
        return;
    }

    pageScriptInfo.referenceCount--;
}

async function initializePageScriptModule(src, pageScriptInfo) {
    if (src.startsWith("./")) {
        src = new URL(src.substr(2), document.baseURI).toString();
    } else {
        src = new URL(src, document.baseURI).toString();
    }

    const module = await import(src);

    if (pageScriptInfo.referenceCount <= 0) {
        return;
    }

    pageScriptInfo.module = module;
    module.onLoad?.();
    module.onUpdate?.();
}

function onEnhancedLoad() {
    for (const [src, {module, referenceCount}] of pageScriptInfoBySrc) {
        if (referenceCount <= 0) {
            module?.onDispose?.();
            pageScriptInfoBySrc.delete(src);
        }
    }

    for (const {module} of pageScriptInfoBySrc.values()) {
        module?.onUpdate?.();
    }
}

export function afterWebStarted(blazor) {
    customElements.define('page-script', class extends HTMLElement {
        static observedAttributes = ['src'];

        attributeChangedCallback(name, oldValue, newValue) {
            if (name !== 'src') {
                return;
            }

            this.src = newValue;
            unregisterPageScriptElement(oldValue);
            registerPageScriptElement(newValue);
        }

        disconnectedCallback() {
            unregisterPageScriptElement(this.src);
        }
    });

    blazor.addEventListener('enhancedload', onEnhancedLoad);
}

Now you have this script in your wwwroot, you now want to create an inline / isolated JS page for one of your Blazor pages or components. All you do is create a .JS file with the same name as the component, but end with .js. As you can see from the image, I have created it under my HomeView.razor (My home page) and created a file called  HomeView.razor.js. Your IDE should nest or connect the files.

And within the HomeView.razor.js file, add the following JS

export function onLoad() {
    console.log('Loaded');
}

export function onUpdate() {
    console.log('Updated');
}

export function onDispose() {
    console.log('Disposed');
}

So we have a .lib file added to the root, and an inline Js file added to my HomeView. The last thing to do is add a PageScript component that renders the inline js files. Add the following component to your project anywhere you like as long as you can reference / use it.

<page-script src="@Src"></page-script>
@code {
    [Parameter, EditorRequired] public string Src { get; set; } = default!;
}

Now you just need to add your PageScript component to your MainLayout.Razor or whatever your main layout page is called at the bottom like so and reference the Javascript file we created earlier. So in my case it's './Pages/HomeView.razor.js' I'm putting the exact location of it within my project (So my HomeView is within a Pages folder).

<PageScript Src="./Pages/HomeView.razor.js" />

Once you have this all setup, you can then make use of the onLoad() and onUpdate() methods. In my case because I have added a link to the CDN for highlight js. I now just need to update it like this

export function onLoad() {
    hljs.highlightAll();
}

export function onUpdate() {
    hljs.highlightAll();
}
© 2025 - Powered By ZauberCMS
An unhandled error has occurred. Reload 🗙