Embedding Existing JavaScript Components Into Uno-WASM - Part 1
HTML5 is a Rich and Powerful Platform
Uno Platform fully embraces HTML5 as its display backend when targeting WebAssembly, for both Native and Skia renderers. As a result, it is possible to integrate with almost any existing JavaScript library to extend the behavior of an app.
Embedding assets
In the HTML world, everything running in the browser is assets that must be downloaded from a server. To integrate existing JavaScript frameworks, they can be either downloaded from another location on the Internet (usually from a CDN service) or embedded and deployed with the app.
The Uno Bootstrapper can automatically embed any asset and deploy it with the app. Some of them (CSS & JavaScript) can also be loaded with the app. Here's how to declare them in a Uno Wasm project:
JavaScript files should be in the
Platforms/WebAssembly/WasmScripts
folder. They will be copied to the output folder and loaded automatically by the bootstrapper when the page loads.CSS Style files should be in the
Platforms/WebAssembly/WasmCSS
folder. They will be copied to the output folder and referenced in the HTML head of the application.Asset files can be placed in the
Assets
folder. These files will be copied to the output folder and will preserve the same relative path to theAssets
folder.Alternatively, any kind of asset file can be placed directly in the
wwwroot
folder as with any standard ASP.NET Core project. They will be deployed with the app, but the application code is responsible for fetching and using them.Is it an ASP.NET Core "web" project? No, but it shares a common structure. Some of the deployment features, like the
wwwroot
folder, and the Visual Studio integration for running/debugging are reused in a similar way to an ASP.NET Core project. The C# code put in the project will run in the browser, using the .NET runtime. There is no need for a server side component in Uno-Wasm projects.
Embedding Native Elements
Embedding native JavaScript elements is done through the Uno.UI.NativeElementHosting.BrowserHtmlElement
class, which serves as an entry point to interact with your native element.
[!IMPORTANT] The
BrowserHtmlElement
class is available on all target frameworks, avoid the need for condition#if
code, yet it is only useable on WebAssembly. You'll need to guard its use by validating the platform with theOperatingSystem
class.
using Uno.UI.NativeElementHosting.BrowserHtmlElement;
public sealed partial class MyControlHost : ContentControl
{
private BrowserHtmlElement? _element;
public MyControlHost()
{
if (OperatingSystem.IsBrowser())
{
_element = BrowserHtmlElement.CreateHtmlElement("div");
Content = _element;
}
else
{
Content = "This control only supported on WebAssembly on the Browser";
}
}
}
This way, your native element is hosted inside a content control of your choosing. You can replace it with any available HTML tag.
Once created, it is possible to interact directly with this element by calling BrowserHtmlElement
methods.
Here is a list of helper methods used to facilitate the integration with the HTML DOM:
The method
element.SetCssStyle()
can be used to set a CSS Style on the HTML element. Example:// Setting only one CSS style _element.SetCssStyle("text-shadow", "2px 2px red"); // Setting many CSS styles at once using C# tuples _element.SetCssStyle(("text-shadow", "2px 2px blue"), ("color", "var(--app-fg-color1)"));
The
element.ClearCssStyle()
method can be used to set CSS styles to their default values. Example:// Reset text-shadow style to its default value _element.ClearCssStyle("text-shadow"); // Reset both text-shadow and color to their default values _element.ClearCssStyle("text-shadow", "color");
The
element.SetHtmlAttribute()
andelement.ClearHtmlAttribute()
methods can be used to set HTML attributes on the element:// Set the "href" attribute of an <a> element _element.SetHtmlAttribute("href", "#section2"); // Set many attributes at once (less interop) _element.SetHtmlAttribute(("target", "_blank"), ("referrerpolicy", "no-referrer")); // Remove attribute from DOM element _element.ClearHtmlAttribute("href"); // Get the value of an attribute of a DOM element var href = _element.GetHtmlAttribute("href");
The
element.SetCssClass()
andelement.UnsetCssClass()
methods can be used to add or remove CSS classes to the HTML Element:// Add the class to element _element.SetCssClass("warning"); // Add many classes at once (less interop) _element.SetCssClass("warning", "level2"); // Remove class from element _element.UnsetCssClass("paused"); // You can also set one class from a list of possible values. // Like a radio-button, like non-selected values will be unset var allClasses = new [] { "Small", "Medium", "Large"}; _element.SetCssClass(allClasses, 2); // set to "Large"
The
element.SetHtmlContent()
method can be used to set arbitrary HTML content as child of the control._element.SetHtmlContent("<h2>Welcome to Uno Platform!</h2>");
Finally, it is possible to make calls from and to JavaScript code by using JSImport/JSExport. The javascript code is directly executed in the context of the browser, giving the ability to perform anything that JavaScript can do. See next section for more details.
Raising custom Javascript events
It's also possible to have Javscript components raise events to be handled by C# code.
From your Javascript or TypeScript code, you can raise events:
// Generate a custom generic event from JavaScript/Typescript
htmlElement.dispatchEvent(new Event("simpleEvent"));
// Generate a custom event with a string payload
const payload = "this is the payload of the event";
htmlElement.dispatchEvent(new CustomEvent("stringEvent", { detail: payload }));
// Generate a custom event with a complex payload
const payload = { property:"value", property2: 1234 };
htmlElement.dispatchEvent(new CustomEvent("complexEvent", { detail: payload }));
Then from your C# code, add the following:
protected override void OnLoaded()
{
// Note: following extensions are in the namespace "Uno.Extensions"
this.RegisterHtmlEventHandler("simpleEvent", OnSimpleEvent);
this.RegisterHtmlEventHandler("stringEvent", OnStringEvent);
this.RegisterHtmlEventHandler("complexEvent", OnComplexEvent);
}
private void OnSimpleEvent(object sender, JSObject args)
{
// You can react on "simpleEvent" here
}
private void OnStringEvent(object sender, JSObject args)
{
// You can react on "stringEvent" here
var detail = args.GetPropertyAsString("detail");
}
private void OnComplexEvent(object sender, JSObject args)
{
// You can react on "complexEvent" here
var detail = args.GetPropertyAsJSObject("detail");
var property = detail?.GetPropertyAsString("property");
var property2 = detail?.GetPropertyAsInt32("property2");
}
🔬 Going further
- Continue with Part 2 - an integration of a syntax highlighter component.
- Continue with Part 3 - an integration of a more complex library with callbacks to application.
- Read the Uno Wasm Bootstrapper documentation.