Use Razor components in JavaScript apps and SPA frameworks
Note
This isn't the latest version of this article. For the current release, see the .NET 8 version of this article.
Warning
This version of ASP.NET Core is no longer supported. For more information, see .NET and .NET Core Support Policy. For the current release, see the .NET 8 version of this article.
Important
This information relates to a pre-release product that may be substantially modified before it's commercially released. Microsoft makes no warranties, express or implied, with respect to the information provided here.
For the current release, see the .NET 8 version of this article.
This article covers how to render Razor components from JavaScript, use Blazor custom elements, and generate Angular and React components.
Note
We recommend using the blazor.server.js
(Blazor Server) and blazor.webassembly.js
(Blazor WebAssembly) scripts when integrating Razor components into an existing JavaScript app until better support for the blazor.web.js
(Blazor Web App) script is added in the future. For more information, see RegisterCustomElement stopped working in Blazor 8 (dotnet/aspnetcore
#53920).
Angular sample apps
- CustomElementsBlazorSample (Blazor Server) (
javiercn/CustomElementsBlazorSample
, branch:blazor-server
): Blazor Server is supported in .NET 8. To migrate this .NET 7 sample to .NET 8, see Migrate from ASP.NET Core 7.0 to 8.0. - CustomElementsBlazorSample (Blazor WebAssembly) (
javiercn/CustomElementsBlazorSample
, branch:blazor-wasm
): To migrate this .NET 7 sample to .NET 8, see Migrate from ASP.NET Core 7.0 to 8.0.
Render Razor components from JavaScript
Razor components can be dynamically-rendered from JavaScript (JS) for existing JS apps.
The example in this section renders the following Razor component into a page via JS.
Quote.razor
:
<div class="m-5 p-5">
<h2>Quote</h2>
<p>@Text</p>
</div>
@code {
[Parameter]
public string? Text { get; set; }
}
In the Program
file, add the namespace for the location of the component.
Call RegisterForJavaScript on the app's root component collection to register a Razor component as a root component for JS rendering.
RegisterForJavaScript includes an overload that accepts the name of a JS function that executes initialization logic (javaScriptInitializer
). The JS function is called once per component registration immediately after the Blazor app starts and before any components are rendered. This function can be used for integration with JS technologies, such as HTML custom elements or a JS-based SPA framework.
One or more initializer functions can be created and called by different component registrations. The typical use case is to reuse the same initializer function for multiple components, which is expected if the initializer function is configuring integration with custom elements or another JS-based SPA framework.
Important
Don't confuse the javaScriptInitializer
parameter of RegisterForJavaScript with JavaScript initializers. The name of the parameter and the JS initializers feature is coincidental.
The following example demonstrates the dynamic registration of the preceding Quote
component with "quote
" as the identifier.
In a Blazor Server app, modify the call to AddServerSideBlazor in the
Program
file:builder.Services.AddServerSideBlazor(options => { options.RootComponents.RegisterForJavaScript<Quote>(identifier: "quote", javaScriptInitializer: "initializeComponent"); });
In a Blazor WebAssembly app, call RegisterForJavaScript on RootComponents in the client-side
Program
file:builder.RootComponents.RegisterForJavaScript<Quote>(identifier: "quote", javaScriptInitializer: "initializeComponent");
Attach the initializer function with name
and parameters
function parameters to the window
object. For demonstration purposes, the following initializeComponent
function logs the name and parameters of the registered component.
wwwroot/jsComponentInitializers.js
:
window.initializeComponent = (name, parameters) => {
console.log({ name: name, parameters: parameters });
}
Render the component from JS into a container element using the registered identifier, passing component parameters as needed.
In the following example:
- The
Quote
component (quote
identifier) is rendered into thequoteContainer
element when theshowQuote
function is called. - A quote string is passed to the component's
Text
parameter.
wwwroot/scripts.js
:
window.showQuote = async () => {
let targetElement = document.getElementById('quoteContainer');
await Blazor.rootComponents.add(targetElement, 'quote',
{
text: "Crow: I have my doubts that this movie is actually 'starring' " +
"anybody. More like, 'camera is generally pointed at.'"
});
}
const btn = document.querySelector("#showQuoteBtn");
btn.addEventListener("click", showQuote);
After the Blazor script is loaded, load the preceding scripts into the JS app:
<script src="_framework/{BLAZOR SCRIPT}"></script>
<script src="jsComponentInitializers.js"></script>
<script src="scripts.js"></script>
In the preceding example, the {BLAZOR SCRIPT}
placeholder is the Blazor script.
In HTML, place the target container element (quoteContainer
). For the demonstration in this section, a button triggers rendering the Quote
component by calling the showQuote
JS function:
<button id="showQuoteBtn">Show Quote</button>
<div id="quoteContainer"></div>
On initialization before any components are rendered, the browser's developer tools console logs the Quote
component's identifier (name
) and parameters (parameters
) when initializeComponent
is called:
Object { name: "quote", parameters: (1) […] }
name: "quote"
parameters: Array [ {…} ]
0: Object { name: "Text", type: "string" }
length: 1
When the Show Quote button is selected, the Quote
component is rendered with the quote stored in Text
displayed:
Quote ©1988-1999 Satellite of Love LLC: Mystery Science Theater 3000 (Trace Beaulieu (Crow))
Note
rootComponents.add
returns an instance of the component. Call dispose
on the instance to release it:
const rootComponent = await window.Blazor.rootComponents.add(...);
...
rootComponent.dispose();
The preceding example dynamically renders the root component when the showQuote()
JS function is called. To render a root component into a container element when Blazor starts, use a JavaScript initializer to render the component, as the following example demonstrates.
The following example builds on the preceding example, using the Quote
component, the root component registration in the Program
file, and the initialization of jsComponentInitializers.js
. The showQuote()
function (and the script.js
file) aren't used.
In HTML, place the target container element, quoteContainer2
for this example:
<div id="quoteContainer2"></div>
Using a JavaScript initializer, add the root component to the target container element.
wwwroot/{PACKAGE ID/ASSEMBLY NAME}.lib.module.js
:
export function afterStarted(blazor) {
let targetElement = document.getElementById('quoteContainer2');
blazor.rootComponents.add(targetElement, 'quote',
{
text: "Crow: I have my doubts that this movie is actually 'starring' " +
"anybody. More like, 'camera is generally pointed at.'"
});
}
Note
For the call to rootComponents.add
, use the blazor
parameter (lowercase b
) provided by the Blazor start event. Although the registration is valid when using the Blazor
object (uppercase B
), the preferred approach is to use the parameter.
For an advanced example with additional features, see the example in the BasicTestApp
of the ASP.NET Core reference source (dotnet/aspnetcore
GitHub repository):
Note
Documentation links to .NET reference source usually load the repository's default branch, which represents the current development for the next release of .NET. To select a tag for a specific release, use the Switch branches or tags dropdown list. For more information, see How to select a version tag of ASP.NET Core source code (dotnet/AspNetCore.Docs #26205).
Blazor custom elements
Use Blazor custom elements to dynamically render Razor components from other SPA frameworks, such as Angular or React.
Blazor custom elements:
- Use standard HTML interfaces to implement custom HTML elements.
- Eliminate the need to manually manage the state and lifecycle of root Razor components using JavaScript APIs.
- Are useful for gradually introducing Razor components into existing projects written in other SPA frameworks.
Custom elements don't support child content or templated components.
Element name
Per the HTML specification, custom element tag names must adopt kebab case:
Invalid: mycounter
Invalid: MY-COUNTER
Invalid: MyCounter
Valid: my-counter
Valid: my-cool-counter
Package
Add a package reference for Microsoft.AspNetCore.Components.CustomElements
to the app's project file.
Note
For guidance on adding packages to .NET apps, see the articles under Install and manage packages at Package consumption workflow (NuGet documentation). Confirm correct package versions at NuGet.org.
Example component
The following examples are based on the Counter
component from the Blazor project template.
Counter.razor
:
@page "/counter"
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount() => currentCount++;
}
Blazor Server registration
Take the following steps to register a root component as a custom element in a Blazor Server app.
Add the Microsoft.AspNetCore.Components.Web namespace to the top of the Program
file:
using Microsoft.AspNetCore.Components.Web;
Add a namespace for the app's components. In the following example, the app's namespace is BlazorSample
and the components are located in the Pages
folder:
using BlazorSample.Pages;
Modify the call to AddServerSideBlazor. Specify the custom element with RegisterCustomElement on the RootComponents circuit option. The following example registers the Counter
component with the custom HTML element my-counter
:
builder.Services.AddServerSideBlazor(options =>
{
options.RootComponents.RegisterCustomElement<Counter>("my-counter");
});
Blazor WebAssembly registration
Take the following steps to register a root component as a custom element in a Blazor WebAssembly app.
Add the Microsoft.AspNetCore.Components.Web namespace to the top of the Program
file:
using Microsoft.AspNetCore.Components.Web;
Add a namespace for the app's components. In the following example, the app's namespace is BlazorSample
and the components are located in the Pages
folder:
using BlazorSample.Pages;
Call RegisterCustomElement on RootComponents. The following example registers the Counter
component with the custom HTML element my-counter
:
builder.RootComponents.RegisterCustomElement<Counter>("my-counter");
Use the registered custom element
Use the custom element with any web framework. For example, the preceding my-counter
custom HTML element that renders the app's Counter
component is used in a React app with the following markup:
<my-counter></my-counter>
For a complete example of how to create custom elements with Blazor, see the CustomElementsComponent
component in the reference source.
Note
Documentation links to .NET reference source usually load the repository's default branch, which represents the current development for the next release of .NET. To select a tag for a specific release, use the Switch branches or tags dropdown list. For more information, see How to select a version tag of ASP.NET Core source code (dotnet/AspNetCore.Docs #26205).
Pass parameters
Pass parameters to your Razor component either as HTML attributes or as JavaScript properties on the DOM element.
The following Counter
component uses an IncrementAmount
parameter to set the increment amount of the Click me button.
Counter.razor
:
@page "/counter"
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
[Parameter]
public int IncrementAmount { get; set; } = 1;
private void IncrementCount()
{
currentCount += IncrementAmount;
}
}
Render the Counter
component with the custom element and pass a value to the IncrementAmount
parameter as an HTML attribute. The attribute name adopts kebab-case syntax (increment-amount
, not IncrementAmount
):
<my-counter increment-amount="10"></my-counter>
Alternatively, you can set the parameter's value as a JavaScript property on the element object. The property name adopts camel case syntax (incrementAmount
, not IncrementAmount
):
const elem = document.querySelector("my-counter");
elem.incrementAmount = 10;
You can update parameter values at any time using either attribute or property syntax.
Supported parameter types:
- Using JavaScript property syntax, you can pass objects of any JSON-serializable type.
- Using HTML attributes, you are limited to passing objects of string, boolean, or numerical types.
Experimental support is available for building custom elements using the Microsoft.AspNetCore.Components.CustomElements
NuGet package. Custom elements use standard HTML interfaces to implement custom HTML elements.
Warning
Experimental features are provided for the purpose of exploring feature viability and may not ship in a stable version.
Register a root component as a custom element:
In a Blazor Server app, modify the call to AddServerSideBlazor in the
Program
file to call RegisterCustomElement on CircuitOptions.RootComponents:builder.Services.AddServerSideBlazor(options => { options.RootComponents.RegisterCustomElement<Counter>("my-counter"); });
Note
The preceding code example requires a namespace for the app's components (for example,
using BlazorSample.Components.Pages;
) in theProgram
file.In a Blazor WebAssembly app, call RegisterCustomElement on WebAssemblyHostBuilder.RootComponents in the
Program
file:builder.RootComponents.RegisterCustomElement<Counter>("my-counter");
Note
The preceding code example requires a namespace for the app's components (for example,
using BlazorSample.Components.Pages;
) in theProgram
file.
Include the following <script>
tag in the app's HTML before the Blazor script tag:
<script src="/_content/Microsoft.AspNetCore.Components.CustomElements/BlazorCustomElements.js"></script>
Use the custom element with any web framework. For example, the preceding counter custom element is used in a React app with the following markup:
<my-counter increment-amount={incrementAmount}></my-counter>
Warning
The custom elements feature is currently experimental, unsupported, and subject to change or be removed at any time. We welcome your feedback on how well this particular approach meets your requirements.
Generate Angular and React components
Generate framework-specific JavaScript (JS) components from Razor components for web frameworks, such as Angular or React. This capability isn't included with .NET, but is enabled by the support for rendering Razor components from JS. The JS component generation sample on GitHub demonstrates how to generate Angular and React components from Razor components. See the GitHub sample app's README.md
file for additional information.
Warning
The Angular and React component features are currently experimental, unsupported, and subject to change or be removed at any time. We welcome your feedback on how well this particular approach meets your requirements.