---
title: "Interacting with JavaScript Objects using the new IJSObjectReference in Blazor"
excerpt: "A new type is introduced in .NET 5 called IJSObjectReference. This type holds a reference to a JavaScript object and can be used to invoke functions available on that JavaScript object."
publishDate: "2020-12-21T00:00:00"
createDate: "2020-12-15T00:06:48.253"
updateDate: "2020-12-21T10:03:15.003"
category: "dotnet"
categoryName: ".NET"
tags: [".NET","ASP.NET","dotnet","aspnet","Blazor",".NET Core","ASP.NET Core","dotnetcore","aspnetcore","C#","CSharp"]
permalink: "/blog/dotnet/interacting-with-javascript-objects-using-the-new-ijsobjectreference-in-blazor"
canonical: "/blog/dotnet/interacting-with-javascript-objects-using-the-new-ijsobjectreference-in-blazor"
image: {"src":"/media/ksbljku3/javascript-in-blazor-ijso-long.png","focalPoint":{"left":0.5,"top":0.5},"crops":[{"alias":"Banner","width":1120,"height":400,"coordinates":null}]}
imageAlt: "Blazor next to JavaScript logo besides title: Interacting with JavaScript Objects using the new IJSObjectReference in Blazor"
imageBackgroundColor: "#fafafa"
thumbnailImage: {"src":"/media/ad2llt0w/javascript-in-blazor-ijso-square.png","focalPoint":{"left":0.4982464937912058,"top":0.4982464937912058},"crops":[{"alias":"thumbnail","width":250,"height":250,"coordinates":null}]}
thumbnailImageAlt: "Blazor next to JavaScript logo"
metaTitle: "Interacting with JavaScript Objects using the new IJSObjectReference in Blazor"
metaDescription: "A new type is introduced in .NET 5 called IJSObjectReference. This type holds a reference to a JavaScript object and can be used to invoke functions available on that JavaScript object."
ogTitle: "Interacting with JavaScript Objects using the new IJSObjectReference in Blazor"
ogDescription: "A new type is introduced in .NET 5 called IJSObjectReference. This type holds a reference to a JavaScript object and can be used to invoke functions available on that JavaScript object."
ogImage: {"src":"/media/iaubntnc/javascript-in-blazor-ijso-social.png","focalPoint":{"left":0.4982464937912058,"top":0.5019834467897546},"crops":[{"alias":"OpenGraph","width":1200,"height":630,"coordinates":null}]}
ogImageAlt: "Blazor next to JavaScript logo besides title: Interacting with JavaScript Objects using the new IJSObjectReference in Blazor"
relatedPostKeys: ["a90267e3e840468cadaf538780dd12c3","7606d5bc3e54480188f355f164bd1ece","3fa142faee1a488c91f507627e8059bb"]
noIndex: false
noFollow: false
sitemapExclude: false
headHtml: |-
  <style>
  iframe{
    width: 100%;
  }

  iframe[src="https://blazorjavascriptinterop.swimburger.net/advanced-interop/embed"],
  iframe[src="https://blazorjavascriptinterop.swimburger.net/advanced-interop-dotnet5/embed"]  {
    height: 800px;
  }

  </style>
source: {"nodeId":1386,"contentKey":"cfa2abb6ee344ac9bbd98ddddb3b138e","sortOrder":70}
---


New API's to interact with JavaScript from .NET were added with the introduction of Blazor. Using these API's you can invoke JavaScript functions from .NET and .NET methods from JavaScript. This is also referred to as '**JavaScript interoperability**'.


The JavaScript interoperability API's provided by Microsoft live under Microsoft.JSInterop namespace. These capabilities were showcased at a previous article: "[Communicating between .NET and JavaScript in Blazor with in-browser samples](https://swimburger.net/blog/dotnet/communicating-between-dotnet-and-javascript-in-blazor-with-in-browser-samples)".


Some additional API's have now been introduced with the release of .NET 5. One very important API in particular was introduced: <code><strong>IJSObjectReference</strong></code>.

## Calling JavaScript functions before IJSObjectReference {#calling-javascript-functions-before-ijsobjectreference}

Using the `IJSRuntime` interface, you can call JavaScript functions from .NET. Here's an example which calls the `prompt` and `alert` JavaScript function on the global `window` object:

<pre style="color:#000000;background:#ffffff;">@inject IJSRuntime JS&#10;&#10;@code {&#10;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#7f0055; font-weight:bold; ">protected</span> <span style="color:#7f0055; font-weight:bold; ">override</span> async Task OnInitializedAsync()&#10;&nbsp;&nbsp;&nbsp;&nbsp;{&#10;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#7f0055; font-weight:bold; ">string</span> name = await JS.InvokeAsync&lt;<span style="color:#7f0055; font-weight:bold; ">string</span>&gt;(<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">prompt</span><span style="color:#2a00ff; ">"</span>, <span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">What is your name?</span><span style="color:#2a00ff; ">"</span>);&#10;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;await JS.InvokeVoidAsync(<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">alert</span><span style="color:#2a00ff; ">"</span>, $<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">Hello {name}!</span><span style="color:#2a00ff; ">"</span>);&#10;&nbsp;&nbsp;&nbsp;&nbsp;}&#10;}&#10;</pre>

This is fairly straightforward, but you can quickly run into the limitations of `IJSRuntime`. Using `IJSRuntime` you can only call JavaScript functions that are available on the global `window` object in the browser. Meanwhile in JavaScript it is very common for one function to return an object holding other functions to invoke.


This is taken to the extreme when JavaScript libraries are designed to be consumed as fluent API's. For example, most of jQuery's functions return a jQuery object which you then call another jQuery function on, which in turn returns a jQuery object, and the cycle continues until broken off. Here's an example of jQuery function chaining:

<pre style="color:#000000;background:#ffffff;"><span style="color:#7f0055; font-weight:bold; ">const</span> currentOrigin = location.origin;&#10;$(<span style="color:#2a00ff; ">`</span><span style="color:#2a00ff; ">a:not([href^="</span><span style="color:#2a00ff; ">${</span><span style="color:#2a00ff; ">currentOrigin</span><span style="color:#2a00ff; ">}</span><span style="color:#2a00ff; ">"])</span><span style="color:#2a00ff; ">`</span>)&#10;&nbsp;&nbsp;.attr(<span style="color:#2a00ff; ">'</span><span style="color:#2a00ff; ">rel</span><span style="color:#2a00ff; ">'</span>, <span style="color:#2a00ff; ">'</span><span style="color:#2a00ff; ">noopener nofollow noreferrer</span><span style="color:#2a00ff; ">'</span>)&#10;&nbsp;&nbsp;.attr(<span style="color:#2a00ff; ">'</span><span style="color:#2a00ff; ">target</span><span style="color:#2a00ff; ">'</span>, <span style="color:#2a00ff; ">'</span><span style="color:#2a00ff; ">_blank</span><span style="color:#2a00ff; ">'</span>)&#10;&nbsp;&nbsp;.addClass(<span style="color:#2a00ff; ">'</span><span style="color:#2a00ff; ">external-link</span><span style="color:#2a00ff; ">'</span>);&nbsp;&#10;</pre>

This script finds all links on the page where the href does not start with the current origin. In other words, any link that points to an external website. Then the `rel` and `target` attribute are modified appropriately. Then the ‘external-link' CSS class is added to style the external link differently.


No sane person would actually try to write this code using Blazor JavaScript interop. Instead, you should wrap the code into a global JavaScript function and invoke it when necessary with JS interop like this: `await JS.InvokeVoidAsync("configureExternalLinks")`


The real challenge starts when you need to invoke JavaScript on state that isn't global or singleton. If you have multiple instances of a Blazor component at the same time, and the component holds some state in JavaScript, your global JavaScript function needs to somehow access the correct component state to perform its functionality. 


In this [Bootstrap Carousel example](https://swimburger.net/blog/dotnet/communicating-between-dotnet-and-javascript-in-blazor-with-in-browser-samples#carousel-component-sample), this is solved by generating a unique id for each component instance. Whenever the Blazor component invokes JavaScript functions, that unique id is passed as a parameter so that the JavaScript can store and fetch the appropriate state:


**JavaScript Source:**

<pre style="color:#000000;background:#ffffff;"><span style="color:#7f0055; font-weight:bold; ">var</span> blazorCarousel = {&#10;    instances: {},&#10;    init: <span style="color:#7f0055; font-weight:bold; ">function</span> (carouselId, dotNetReference, carouselNode) {&#10;        <span style="color:#7f0055; font-weight:bold; ">var</span> carousel = {&#10;            dotNetReference: dotNetReference,&#10;            $carouselNode: $(carouselNode)&#10;        };&#10;        carousel.$carouselNode.carousel();&#10;        carousel.$carouselNode.on(<span style="color:#2a00ff; ">'</span><span style="color:#2a00ff; ">slide.bs.carousel</span><span style="color:#2a00ff; ">'</span>, <span style="color:#7f0055; font-weight:bold; ">function</span> (event) {&#10;            dotNetReference.invokeMethod(<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">OnSlide</span><span style="color:#2a00ff; ">"</span>, event.direction, event.from, event.to);&#10;        });&#10;        carousel.$carouselNode.on(<span style="color:#2a00ff; ">'</span><span style="color:#2a00ff; ">slid.bs.carousel</span><span style="color:#2a00ff; ">'</span>, <span style="color:#7f0055; font-weight:bold; ">function</span> (event) {&#10;            dotNetReference.invokeMethod(<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">OnSlid</span><span style="color:#2a00ff; ">"</span>, event.direction, event.from, event.to);&#10;        });&#10;        <span style="color:#7f0055; font-weight:bold; ">this</span>.instances[carouselId] = carousel;&#10;    },&#10;    dispose: <span style="color:#7f0055; font-weight:bold; ">function</span> (carouselId) {&#10;        <span style="color:#7f0055; font-weight:bold; ">this</span>.instances[carouselId].$carouselNode.carousel(<span style="color:#2a00ff; ">'</span><span style="color:#2a00ff; ">dispose</span><span style="color:#2a00ff; ">'</span>);&#10;        <span style="color:#7f0055; font-weight:bold; ">delete</span> <span style="color:#7f0055; font-weight:bold; ">this</span>.instances[carouselId];&#10;    }&#10;};&#10;</pre>

**Blazor Source:**

<pre style="color:#000000;background:#ffffff;">@implements IDisposable&#10;@using Microsoft.Extensions.Logging&#10;@inject IJSRuntime js&#10;@inject ILogger<span style="color:#7f0055; ">&lt;</span><span style="color:#7f0055; ">Carousel</span><span style="color:#7f0055; ">&gt;</span> logger&#10;<span style="color:#7f0055; ">&lt;</span><span style="color:#7f0055; font-weight:bold; ">div</span> class=<span style="color:#2a00ff; ">"carousel slide"</span> data-ride=<span style="color:#2a00ff; ">"carousel"</span> id=<span style="color:#2a00ff; ">"@carouselId"</span> @ref=<span style="color:#2a00ff; ">"carouselReference"</span><span style="color:#7f0055; ">&gt;</span>&#10;  <span style="color:#7f0055; ">&lt;</span><span style="color:#7f0055; font-weight:bold; ">div</span> class=<span style="color:#2a00ff; ">"carousel-inner"</span><span style="color:#7f0055; ">&gt;</span>&#10;    @for (int i = 1; i &lt;= 10; i++)&#10;    {&#10;      <span style="color:#7f0055; ">&lt;</span><span style="color:#7f0055; font-weight:bold; ">div</span> class=<span style="color:#2a00ff; ">"carousel-item @(i == 1 ? "</span>active<span style="color:#2a00ff; ">": "</span><span style="color:#2a00ff; ">")"</span><span style="color:#7f0055; ">&gt;</span>&#10;        <span style="color:#7f0055; ">&lt;</span><span style="color:#7f0055; font-weight:bold; ">svg</span> class=<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">bd-placeholder-img bd-placeholder-img-lg d-block w-100</span><span style="color:#2a00ff; ">"</span> width=<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">800</span><span style="color:#2a00ff; ">"</span> height=<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">400</span><span style="color:#2a00ff; ">"</span><span style="color:#7f0055; ">&gt;</span>&#10;          <span style="color:#3f7f59; ">&lt;!--</span><span style="color:#3f7f59; "> SVG image content goes here </span><span style="color:#3f7f59; ">--&gt;</span>&#10;        <span style="color:#7f0055; ">&lt;/</span><span style="color:#7f0055; font-weight:bold; ">svg</span><span style="color:#7f0055; ">&gt;</span>&#10;      <span style="color:#7f0055; ">&lt;/</span><span style="color:#7f0055; font-weight:bold; ">div</span><span style="color:#7f0055; ">&gt;</span>&#10;    }&#10;  <span style="color:#7f0055; ">&lt;/</span><span style="color:#7f0055; font-weight:bold; ">div</span><span style="color:#7f0055; ">&gt;</span>&#10;  <span style="color:#7f0055; ">&lt;</span><span style="color:#7f0055; font-weight:bold; ">a</span> class=<span style="color:#2a00ff; ">"carousel-control-prev"</span> data-target=<span style="color:#2a00ff; ">"#@carouselId"</span> role=<span style="color:#2a00ff; ">"button"</span> data-slide=<span style="color:#2a00ff; ">"prev"</span><span style="color:#7f0055; ">&gt;</span>&#10;    <span style="color:#7f0055; ">&lt;</span><span style="color:#7f0055; font-weight:bold; ">span</span> class=<span style="color:#2a00ff; ">"carousel-control-prev-icon"</span> aria-hidden=<span style="color:#2a00ff; ">"true"</span><span style="color:#7f0055; ">&gt;</span><span style="color:#7f0055; ">&lt;/</span><span style="color:#7f0055; font-weight:bold; ">span</span><span style="color:#7f0055; ">&gt;</span>&#10;    <span style="color:#7f0055; ">&lt;</span><span style="color:#7f0055; font-weight:bold; ">span</span> class=<span style="color:#2a00ff; ">"sr-only"</span><span style="color:#7f0055; ">&gt;</span>Previous<span style="color:#7f0055; ">&lt;/</span><span style="color:#7f0055; font-weight:bold; ">span</span><span style="color:#7f0055; ">&gt;</span>&#10;  <span style="color:#7f0055; ">&lt;/</span><span style="color:#7f0055; font-weight:bold; ">a</span><span style="color:#7f0055; ">&gt;</span>&#10;  <span style="color:#7f0055; ">&lt;</span><span style="color:#7f0055; font-weight:bold; ">a</span> class=<span style="color:#2a00ff; ">"carousel-control-next"</span> data-target=<span style="color:#2a00ff; ">"#@carouselId"</span> role=<span style="color:#2a00ff; ">"button"</span> data-slide=<span style="color:#2a00ff; ">"next"</span><span style="color:#7f0055; ">&gt;</span>&#10;    <span style="color:#7f0055; ">&lt;</span><span style="color:#7f0055; font-weight:bold; ">span</span> class=<span style="color:#2a00ff; ">"carousel-control-next-icon"</span> aria-hidden=<span style="color:#2a00ff; ">"true"</span><span style="color:#7f0055; ">&gt;</span><span style="color:#7f0055; ">&lt;/</span><span style="color:#7f0055; font-weight:bold; ">span</span><span style="color:#7f0055; ">&gt;</span>&#10;    <span style="color:#7f0055; ">&lt;</span><span style="color:#7f0055; font-weight:bold; ">span</span> class=<span style="color:#2a00ff; ">"sr-only"</span><span style="color:#7f0055; ">&gt;</span>Next<span style="color:#7f0055; ">&lt;/</span><span style="color:#7f0055; font-weight:bold; ">span</span><span style="color:#7f0055; ">&gt;</span>&#10;  <span style="color:#7f0055; ">&lt;/</span><span style="color:#7f0055; font-weight:bold; ">a</span><span style="color:#7f0055; ">&gt;</span>&#10;<span style="color:#7f0055; ">&lt;/</span><span style="color:#7f0055; font-weight:bold; ">div</span><span style="color:#7f0055; ">&gt;</span>&#10;&#10;@code{&#10;  <span style="color:#3f7f59; ">// prefix id with 'id_' to make sure id's don't start with a number or other invalid character</span>&#10;  <span style="color:#3f7f59; ">// add Guid to ensure unique-ness but remove '-' as they are invalid characters for JS property names</span>&#10;  <span style="color:#7f0055; font-weight:bold; ">private</span> <span style="color:#7f0055; font-weight:bold; ">string</span> carouselId = $<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">id_{Guid.NewGuid().ToString().Replace(</span><span style="color:#2a00ff; ">"</span>-<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">, </span><span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">)}</span><span style="color:#2a00ff; ">"</span>;&#10;  <span style="color:#7f0055; font-weight:bold; ">private</span> ElementReference carouselReference;&#10;  <span style="color:#7f0055; font-weight:bold; ">private</span> DotNetObjectReference&lt;Carousel&gt; dotNetObjectReference;&#10;&#10;  <span style="color:#7f0055; font-weight:bold; ">protected</span> <span style="color:#7f0055; font-weight:bold; ">override</span> async Task OnAfterRenderAsync(<span style="color:#7f0055; font-weight:bold; ">bool</span> firstRender)&#10;  {&#10;    <span style="color:#7f0055; font-weight:bold; ">if</span> (firstRender)&#10;    {&#10;      dotNetObjectReference = DotNetObjectReference.Create(<span style="color:#7f0055; font-weight:bold; ">this</span>);&#10;      await js.InvokeVoidAsync(<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">blazorCarousel.init</span><span style="color:#2a00ff; ">"</span>, carouselId, dotNetObjectReference, carouselReference);&#10;    }&#10;  }&#10;&#10;  [JSInvokable]&#10;  <span style="color:#7f0055; font-weight:bold; ">public</span> <span style="color:#7f0055; font-weight:bold; ">void</span> OnSlide(<span style="color:#7f0055; font-weight:bold; ">string</span> direction, <span style="color:#7f0055; font-weight:bold; ">int</span> from, <span style="color:#7f0055; font-weight:bold; ">int</span> to)&#10;  {&#10;    logger.LogInformation($<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">Carousel is sliding from {from} to {to}.</span><span style="color:#2a00ff; ">"</span>);&#10;  }&#10;&#10;  [JSInvokable]&#10;  <span style="color:#7f0055; font-weight:bold; ">public</span> <span style="color:#7f0055; font-weight:bold; ">void</span> OnSlid(<span style="color:#7f0055; font-weight:bold; ">string</span> direction, <span style="color:#7f0055; font-weight:bold; ">int</span> from, <span style="color:#7f0055; font-weight:bold; ">int</span> to)&#10;  {&#10;    logger.LogInformation($<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">Carousel slid from {from} to {to}.</span><span style="color:#2a00ff; ">"</span>);&#10;  }&#10;&#10;  <span style="color:#7f0055; font-weight:bold; ">public</span> <span style="color:#7f0055; font-weight:bold; ">void</span> Dispose()&#10;  {&#10;    <span style="color:#3f7f59; ">// IAsyncDisposable not supported yet in .NET Core 3.1</span>&#10;    Task.Run(() =&gt; js.InvokeVoidAsync(<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">blazorCarousel.dispose</span><span style="color:#2a00ff; ">"</span>, carouselId));&#10;    dotNetObjectReference.Dispose();&#10;  }&#10;}&#10;</pre>
<p><strong>Live Sample:</strong><a href="https://blazorjavascriptinterop.swimburger.net/advanced-interop/embed"></a></p>
<iframe loading="lazy" src="https://blazorjavascriptinterop.swimburger.net/advanced-interop/embed" title="Embedded content">&#10;</iframe>
<p>For more details on this component, read the explanation at "<a href="https://swimburger.net/blog/dotnet/communicating-between-dotnet-and-javascript-in-blazor-with-in-browser-samples#carousel-component-sample">Communicating between .NET and JavaScript in Blazor with in-browser samples</a>".</p>




Generating a unique ID, passing it to every single JavaScript function, and then developing your JavaScript to manage the state in a global object is a very cumbersome way to deal with the limitation of `IJSRuntime`. In .NET Core 3.1, there's no way around doing this, but in .NET 5 you can now use `IJSObjectReference`.

## Calling JavaScript functions with IJSObjectReference {#calling-javascript-functions-with-ijsobjectreference}

`IJSObjectReference` is a new type introduced with .NET 5 which holds a reference to a JavaScript object and has the same methods as `IJSRuntime` to invoke JavaScript functions.<br>But whereas `IJSRuntime` invokes the JavaScript functions available on the `window` object, `IJSObjectReference` will invoke the JavaScript functions available on that JavaScript object.


The way you can obtain an instance of `IJSObjectReference`, is by calling a JavaScript function using `IJSRuntime` which returns a JavaScript object. In .NET, you have to specify `IJSObjectReference` as the generic type parameter. Here's an example:

<pre style="color:#000000;background:#ffffff;"><span style="color:#7f0055; font-weight:bold; ">var</span> objectReference = await JS.InvokeAsync&lt;IJSObjectReference&gt;(<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">getJavaScriptObject</span><span style="color:#2a00ff; ">"</span>);&#10;</pre>

Now that you have the reference to a JavaScript object, you can invoke its functions like this:

<pre style="color:#000000;background:#ffffff;">await objectReference.InvokeVoidAsync(<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">doSomething</span><span style="color:#2a00ff; ">"</span>);&#10;</pre>

This means you can now update the Bootstrap Carousel code to be more concise and intuitive.<br>You'll still need to generate a unique id, but only for the purpose of the Carousel's HTML attributes. Instead of passing that unique id to every JavaScript function, you can add a JavaScript function that creates a JavaScript object holding onto the state and functions.


**JavaScript Source:**

<pre style="color:#000000;background:#ffffff;"><span style="color:#7f0055; font-weight:bold; ">var</span> createBlazorCarousel = <span style="color:#7f0055; font-weight:bold; ">function</span>(){&#10;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#7f0055; font-weight:bold; ">return</span> {&#10;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dotNetReference: <span style="color:#7f0055; font-weight:bold; ">null</span>,&#10;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$carouselNode: <span style="color:#7f0055; font-weight:bold; ">null</span>,&#10;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;init: <span style="color:#7f0055; font-weight:bold; ">function</span> (dotNetReference, carouselNode) {&#10;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#7f0055; font-weight:bold; ">this</span>.dotNetReference = dotNetReference;&#10;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#7f0055; font-weight:bold; ">this</span>.$carouselNode = $(carouselNode);&#10;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#7f0055; font-weight:bold; ">this</span>.$carouselNode.carousel();&#10;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#7f0055; font-weight:bold; ">this</span>.$carouselNode.on(<span style="color:#2a00ff; ">'</span><span style="color:#2a00ff; ">slide.bs.carousel</span><span style="color:#2a00ff; ">'</span>, <span style="color:#7f0055; font-weight:bold; ">function</span> (event) {&#10;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dotNetReference.invokeMethod(<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">OnSlide</span><span style="color:#2a00ff; ">"</span>, event.direction, event.from, event.to);&#10;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});&#10;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#7f0055; font-weight:bold; ">this</span>.$carouselNode.on(<span style="color:#2a00ff; ">'</span><span style="color:#2a00ff; ">slid.bs.carousel</span><span style="color:#2a00ff; ">'</span>, <span style="color:#7f0055; font-weight:bold; ">function</span> (event) {&#10;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dotNetReference.invokeMethod(<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">OnSlid</span><span style="color:#2a00ff; ">"</span>, event.direction, event.from, event.to);&#10;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});&#10;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},&#10;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dispose: <span style="color:#7f0055; font-weight:bold; ">function</span> () {&#10;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#7f0055; font-weight:bold; ">this</span>.$carouselNode.carousel(<span style="color:#2a00ff; ">'</span><span style="color:#2a00ff; ">dispose</span><span style="color:#2a00ff; ">'</span>);&#10;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&#10;&nbsp;&nbsp;&nbsp;&nbsp;}&#10;}&#10;</pre>

**Blazor Source:**

<pre style="color:#000000;background:#ffffff;">@implements IAsyncDisposable&#10;@using Microsoft.Extensions.Logging&#10;@inject IJSRuntime js&#10;@inject ILogger<span style="color:#7f0055; ">&lt;</span><span style="color:#7f0055; ">CarouselV2</span><span style="color:#7f0055; ">&gt;</span> logger&#10;<span style="color:#7f0055; ">&lt;</span><span style="color:#7f0055; font-weight:bold; ">div</span> class=<span style="color:#2a00ff; ">"carousel slide"</span> data-ride=<span style="color:#2a00ff; ">"carousel"</span> id=<span style="color:#2a00ff; ">"@carouselId"</span> @ref=<span style="color:#2a00ff; ">"carouselReference"</span><span style="color:#7f0055; ">&gt;</span>&#10;  <span style="color:#7f0055; ">&lt;</span><span style="color:#7f0055; font-weight:bold; ">div</span> class=<span style="color:#2a00ff; ">"carousel-inner"</span><span style="color:#7f0055; ">&gt;</span>&#10;    @for (int i = 1; i &lt;= 10; i++)&#10;    {&#10;      <span style="color:#7f0055; ">&lt;</span><span style="color:#7f0055; font-weight:bold; ">div</span> class=<span style="color:#2a00ff; ">"carousel-item @(i == 1 ? "</span>active<span style="color:#2a00ff; ">": "</span><span style="color:#2a00ff; ">")"</span><span style="color:#7f0055; ">&gt;</span>&#10;        <span style="color:#7f0055; ">&lt;</span><span style="color:#7f0055; font-weight:bold; ">svg</span> class=<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">bd-placeholder-img bd-placeholder-img-lg d-block w-100</span><span style="color:#2a00ff; ">"</span> width=<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">800</span><span style="color:#2a00ff; ">"</span> height=<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">400</span><span style="color:#2a00ff; ">"</span><span style="color:#7f0055; ">&gt;</span>&#10;          <span style="color:#3f7f59; ">&lt;!--</span><span style="color:#3f7f59; "> SVG image content goes here </span><span style="color:#3f7f59; ">--&gt;</span>&#10;        <span style="color:#7f0055; ">&lt;/</span><span style="color:#7f0055; font-weight:bold; ">svg</span><span style="color:#7f0055; ">&gt;</span>&#10;      <span style="color:#7f0055; ">&lt;/</span><span style="color:#7f0055; font-weight:bold; ">div</span><span style="color:#7f0055; ">&gt;</span>&#10;    }&#10;  <span style="color:#7f0055; ">&lt;/</span><span style="color:#7f0055; font-weight:bold; ">div</span><span style="color:#7f0055; ">&gt;</span>&#10;  <span style="color:#7f0055; ">&lt;</span><span style="color:#7f0055; font-weight:bold; ">a</span> class=<span style="color:#2a00ff; ">"carousel-control-prev"</span> data-target=<span style="color:#2a00ff; ">"#@carouselId"</span> role=<span style="color:#2a00ff; ">"button"</span> data-slide=<span style="color:#2a00ff; ">"prev"</span><span style="color:#7f0055; ">&gt;</span>&#10;    <span style="color:#7f0055; ">&lt;</span><span style="color:#7f0055; font-weight:bold; ">span</span> class=<span style="color:#2a00ff; ">"carousel-control-prev-icon"</span> aria-hidden=<span style="color:#2a00ff; ">"true"</span><span style="color:#7f0055; ">&gt;</span><span style="color:#7f0055; ">&lt;/</span><span style="color:#7f0055; font-weight:bold; ">span</span><span style="color:#7f0055; ">&gt;</span>&#10;    <span style="color:#7f0055; ">&lt;</span><span style="color:#7f0055; font-weight:bold; ">span</span> class=<span style="color:#2a00ff; ">"sr-only"</span><span style="color:#7f0055; ">&gt;</span>Previous<span style="color:#7f0055; ">&lt;/</span><span style="color:#7f0055; font-weight:bold; ">span</span><span style="color:#7f0055; ">&gt;</span>&#10;  <span style="color:#7f0055; ">&lt;/</span><span style="color:#7f0055; font-weight:bold; ">a</span><span style="color:#7f0055; ">&gt;</span>&#10;  <span style="color:#7f0055; ">&lt;</span><span style="color:#7f0055; font-weight:bold; ">a</span> class=<span style="color:#2a00ff; ">"carousel-control-next"</span> data-target=<span style="color:#2a00ff; ">"#@carouselId"</span> role=<span style="color:#2a00ff; ">"button"</span> data-slide=<span style="color:#2a00ff; ">"next"</span><span style="color:#7f0055; ">&gt;</span>&#10;    <span style="color:#7f0055; ">&lt;</span><span style="color:#7f0055; font-weight:bold; ">span</span> class=<span style="color:#2a00ff; ">"carousel-control-next-icon"</span> aria-hidden=<span style="color:#2a00ff; ">"true"</span><span style="color:#7f0055; ">&gt;</span><span style="color:#7f0055; ">&lt;/</span><span style="color:#7f0055; font-weight:bold; ">span</span><span style="color:#7f0055; ">&gt;</span>&#10;    <span style="color:#7f0055; ">&lt;</span><span style="color:#7f0055; font-weight:bold; ">span</span> class=<span style="color:#2a00ff; ">"sr-only"</span><span style="color:#7f0055; ">&gt;</span>Next<span style="color:#7f0055; ">&lt;/</span><span style="color:#7f0055; font-weight:bold; ">span</span><span style="color:#7f0055; ">&gt;</span>&#10;  <span style="color:#7f0055; ">&lt;/</span><span style="color:#7f0055; font-weight:bold; ">a</span><span style="color:#7f0055; ">&gt;</span>&#10;<span style="color:#7f0055; ">&lt;/</span><span style="color:#7f0055; font-weight:bold; ">div</span><span style="color:#7f0055; ">&gt;</span>&#10;&#10;&#10;&#10;@code{&#10;  <span style="color:#3f7f59; ">// prefix id with 'id_' to make sure id's don't start with a number or other invalid character</span>&#10;  <span style="color:#3f7f59; ">// add Guid to ensure unique-ness but remove '-' as they are invalid characters for JS property names</span>&#10;  <span style="color:#7f0055; font-weight:bold; ">private</span> <span style="color:#7f0055; font-weight:bold; ">string</span> carouselId = $<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">id_{Guid.NewGuid().ToString().Replace(</span><span style="color:#2a00ff; ">"</span>-<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">, </span><span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">)}</span><span style="color:#2a00ff; ">"</span>;&#10;  <span style="color:#7f0055; font-weight:bold; ">private</span> ElementReference carouselReference;&#10;  <span style="color:#7f0055; font-weight:bold; ">private</span> DotNetObjectReference&lt;CarouselV2&gt; dotNetObjectReference;&#10;  <span style="color:#7f0055; font-weight:bold; ">private</span> IJSObjectReference carouselJSObjectReference;&#10;&#10;  <span style="color:#7f0055; font-weight:bold; ">protected</span> <span style="color:#7f0055; font-weight:bold; ">override</span> async Task OnAfterRenderAsync(<span style="color:#7f0055; font-weight:bold; ">bool</span> firstRender)&#10;  {&#10;    <span style="color:#7f0055; font-weight:bold; ">if</span> (firstRender)&#10;    {&#10;      dotNetObjectReference = DotNetObjectReference.Create(<span style="color:#7f0055; font-weight:bold; ">this</span>);&#10;      carouselJSObjectReference = await js.InvokeAsync&lt;IJSObjectReference&gt;(<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">createBlazorCarousel</span><span style="color:#2a00ff; ">"</span>);&#10;      await carouselJSObjectReference.InvokeVoidAsync(<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">init</span><span style="color:#2a00ff; ">"</span>, dotNetObjectReference, carouselReference);&#10;    }&#10;  }&#10;&#10;  [JSInvokable]&#10;  <span style="color:#7f0055; font-weight:bold; ">public</span> <span style="color:#7f0055; font-weight:bold; ">void</span> OnSlide(<span style="color:#7f0055; font-weight:bold; ">string</span> direction, <span style="color:#7f0055; font-weight:bold; ">int</span> from, <span style="color:#7f0055; font-weight:bold; ">int</span> to)&#10;  {&#10;    logger.LogInformation($<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">Carousel is sliding from {from} to {to}.</span><span style="color:#2a00ff; ">"</span>);&#10;  }&#10;&#10;  [JSInvokable]&#10;  <span style="color:#7f0055; font-weight:bold; ">public</span> <span style="color:#7f0055; font-weight:bold; ">void</span> OnSlid(<span style="color:#7f0055; font-weight:bold; ">string</span> direction, <span style="color:#7f0055; font-weight:bold; ">int</span> from, <span style="color:#7f0055; font-weight:bold; ">int</span> to)&#10;  {&#10;    logger.LogInformation($<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">Carousel slid from {from} to {to}.</span><span style="color:#2a00ff; ">"</span>);&#10;  }&#10;&#10;  <span style="color:#7f0055; font-weight:bold; ">public</span> async ValueTask DisposeAsync()&#10;  {&#10;    await carouselJSObjectReference.InvokeVoidAsync(<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">dispose</span><span style="color:#2a00ff; ">"</span>);&#10;    await carouselJSObjectReference.DisposeAsync();&#10;    dotNetObjectReference.Dispose();&#10;  }&#10;}&#10;</pre>
<p><strong>Live Sample:</strong></p>
<iframe loading="lazy" src="https://blazorjavascriptinterop.swimburger.net/advanced-interop-dotnet5/embed" title="Embedded content">&#10;</iframe>

## Summary {#summary}

`IJSRuntime` allows you to call JavaScript functions from .NET in Blazor, but only functions that are available on the global `window` object. You cannot call JavaScript functions on objects returned from a function in .NET Core 3.1. You can work around this limitation by storing identifiers on the .NET side and pass them to global JavaScript functions, but this can be very cumbersome. Writing more global JavaScript functions to call the many nested objects and functions is increasingly hard as the complexity of your application increases.


Luckily, a new type is introduced in .NET 5 called `IJSObjectReference`. This type holds a reference to a JavaScript object and can be used to invoke functions available on that JavaScript object. To obtain an instance of `IJSObjectReference`, you can call a JavaScript function using the `IJSRuntime` methods. The JavaScript function has to return a JavaScript object and you have to specify `IJSObjectReference` as the generic type parameter on `IJSRuntime.InvokeAsync`.<br>With `IJSObjectReference` you can now hold onto JavaScript state more easily and write more intuitive JavaScript interop code.
