Ostomachion.Blazor.WebComponents.Generators
0.1.1
dotnet add package Ostomachion.Blazor.WebComponents.Generators --version 0.1.1
NuGet\Install-Package Ostomachion.Blazor.WebComponents.Generators -Version 0.1.1
<PackageReference Include="Ostomachion.Blazor.WebComponents.Generators" Version="0.1.1" />
paket add Ostomachion.Blazor.WebComponents.Generators --version 0.1.1
#r "nuget: Ostomachion.Blazor.WebComponents.Generators, 0.1.1"
// Install Ostomachion.Blazor.WebComponents.Generators as a Cake Addin #addin nuget:?package=Ostomachion.Blazor.WebComponents.Generators&version=0.1.1 // Install Ostomachion.Blazor.WebComponents.Generators as a Cake Tool #tool nuget:?package=Ostomachion.Blazor.WebComponents.Generators&version=0.1.1
BlazorWebComponents
A simple library that allows Blazor components to be rendered as real standards-based Web Components using custom elements, shadow DOM, and HTML templates.
Still in development, but mostly tested and functional for Blazor WebAssembly projects.
TL;DR
Follow the installation and setup sections.
Modify the call to
AddBlazorWebComponents
to the following:builder.Services.AddBlazorWebComponents(r => r.RegisterAll(Assembly.GetExecutingAssembly())});
Add a new Razor Component to your project:
MyComponent.razor
@inherits CustomElementBase <p class="shadow">Shadow: @Value</p> <p class="light">Light: <Slot Name="value" For="Value"/></p>
MyComponent.razor.cs
namespace My.Namespace; [CustomElement("my-component")] public class MyComponent : WebComponent { [Parameter] [EditorRequired] public string Value { get; set; } = default!; }
MyComponent.razor.css
.shadow { background: lightgray; } .light { background: lightyellow; }
Add the component to the main page.
<MyComponent Value="Hello, world!" />
That's it! You've got a full standards-based web component from Blazor!
Rendered output
<my-component>
#shadowroot (open)
<style>
.shadow { background: lightgray; }
.light { background: lightyellow; }
</style>
<p class="shadow">Shadow: Hello, world!</p>
<p class="light">Light: <slot name="value"></slot></p>
<span slot="value">Hello, world!</span>
</my-component>
Installation
dotnet add package Ostomachion.Blazor.WebComponents
Setup
First, follow the installation and setup instructions for Ostomachion.Blazor.ShadowDom. (This will be included automatically in a future release.)
WebAssembly
In wwwroot/index.html
, add the following script:
<script src="_content/Ostomachion.Blazor.WebComponents/blazor-web-components.js"></script>
In Program.cs
, add the following lines:
builder.RootComponents.Add<CustomElementRegistrarComponent>("head::after");
builder.Services.AddBlazorWebComponents();
Server
Note: Blazor Web Components has not yet been thoroughly tested with Blazor server.
In Pages/_Host.html
, add the following script:
<script src="_content/Ostomachion.Blazor.WebComponents/blazor-web-components.js"></script>
In Program.cs
, add the following lines:
builder.Services.AddBlazorWebComponents();
In Pages/_Host.cs
add the following line to the end of the head
element:
<component type="typeof(CustomElementRegistrarComponent)" render-mode="ServerPrerendered" />
MAUI
Note: Blazor Web Components has not yet been thoroughly tested with MAUI/Blazor WebView.
In wwwroot/index.html
, add the following script:
<script src="_content/Ostomachion.Blazor.WebComponents/blazor-web-components.js"></script>
In MauiProgram.cs
add the following line:
builder.Services.AddBlazorWebComponents();
In MainPage.xaml
, in the BlazorWebView.RootComponents
element, add the
following line:
<RootComponent Selector="head::after" ComponentType="{x:Type Ostomachion.BlazorWebComponents.CustomElementRegistrarComponent}" />
Custom Elements
Creating a Custom Element Component
Note: Custom elements must be registered before they can be rendered on a page.
Important: Please read and understand the notes on technical limitations.
Any component class that inherits Ostomachion.WebComponents.CustomElementBase
will be rendered inside a custom element.
By default, custom elements are rendered as autonomous custom elements with an identifier generated from the component's class and namespace. (Example)
The default identifier can be specified using a CustomElementAtrribute
.
(Example)
A customized built-in element can be created using a CustomElementAttribute
.
(Example)
If a reference to the generated custom element is stored in the Host
property
of the component.
Attributes on the generated custom element can be set using the HostAttributes
property of the component. (Example)
Registering Custom Elements
Before a custom element component can be rendered on a page, it must be
registered by passing an action to the call to AddBlazorWebComponents
.
(Example)
To avoid identifier collisions and to allow more customization, an identifier can be registered with the component which will override any default identifier defined by the component itself. (Example)
For convenience, all custom elements in an assembly can be registered at once
using their default identifiers by calling RegisterAll
. Any custom elements that
have already been registered will be skipped by RegisterAll
.
(Example)
Web Components
Web Components are extensions of custom elements with many extra features. Everything in the Custom Elements section applies to web components including registration.
In addition to being wrapped in a custom element, web components are also rendered in a shadow DOM and make use of templates and slots.
Creating a Web Component
Any component class that inherits Ostomachion.WebComponents.WebComponentBase
will be rendered inside a shadow DOM attached to custom element.
(Example)
By default, an open shadow root is attached to the host element. The shadow root
mode can be specified by overriding the ShadowRootMode
property on the
component.
(Example)
Any CSS file associated with the class will be automatically encapsulated in the shadow root. (Example)
Slots
By default, the content of a web component is rendered in the shadow DOM and generally encapsulated from CSS and JavaScript outside the component.
Notes on CSS
Since the host element name of a custom element component can vary, CSS selectors become fragile. As a workaround, this library adds custom namespaced elements to custom elements. The attribute name is equal to the class name in lowercase with a namespace equal to the namespace of the class in lowercase. This not only provides a unique name for each component, it more closely matches the source Razor file. (Example)
⚠️ Notes on Technical Limitations ⚠️
Be aware of the following limitations:
- A component that inherits either
CustomElementBase
orWebComponentBase
MUST declare the base class in the.cs
file (and the.razor
file if one exists). - A
CustomElementAttribute
MUST be applied to the class in the.cs
file and not in the.razor
file. - Any properties with a
SlotAttribute
MUST be defined in the.cs
file and not in the.razor
file.
Adding <UseRazorSourceGenerator>false</UseRazorSourceGenerator>
to the .csproj
should in theory fix these limitations, but this is not a priority to support.
Please report any issue if you need this feature.
Explanation: Some of the functionality of this library is implemented as a C#
source generator. Unfortunately, there is currently no great way to get source
generators to work will with Razor files. This means that the Blazor Web Component
source generator will not work properly if you add certain features to the
.razor
side of a component rather than the .cs
side.
Examples
Basic Custom Element
Test.razor
@inherits CustomElementBase
<p>Hello, world!</p>
Example.razor.cs
namespace Example;
public class Test : CustomElementBase { }
Rendered output
<example-customelementbase>
<p>Hello, world!</p>
</example-customelementbase>
Custom Default Identifier
The default identifier can be changed by adding a CustomElementAttribute
to the
class.
Test.razor
@inherits CustomElementBase
<p>Hello, world!</p>
Example.razor.cs
namespace Example;
[CustomElement("docs-test")]
public class Test : CustomElementBase { }
Rendered output
<docs-test>
<p>Hello, world!</p>
</docs-test>
Customized Built-In Element
A customized built-in element can be created by adding a
CustomElementAttribute
to the class.
Test.razor
@inherits CustomElementBase
<p>Hello, world!</p>
Example.razor.cs
namespace Example;
[CustomElement("docs-test", Extends = "div")]
public class Test : CustomElementBase { }
Rendered output
<div is="docs-test">
<p>Hello, world!</p>
</div>
Adding Host Attributes
Attributes can be set on the generated custom element using the HostAttributes
property.
Test.razor
@inherits CustomElementBase
@HostAttributes["id"] = "host"
<p>Hello, world!</p>
Example.razor.cs
namespace Example;
[CustomElement("docs-test")]
public class Test : CustomElementBase { }
Rendered output
<docs-test id="host">
<p>Hello, world!</p>
</docs-test>
Basic Registration
A custom element must be registered before it can be rendered on a page.
Test.razor
@inherits CustomElementBase
<p>Hello, world!</p>
Example.razor.cs
namespace Example;
[CustomElement("docs-test")]
public class Test : CustomElementBase { }
Program.cs / MauiProgram.cs
...
builder.Services.AddBlazorWebComponents(r =>
{
r.Register<Test>();
});
...
Rendered output
<docs-test>
<p>Hello, world!</p>
</docs-test>
Identifier Registration
The default identifier of a custom element can be overridden at registration.
Test.razor
@inherits CustomElementBase
<p>Hello, world!</p>
Example.razor.cs
namespace Example;
[CustomElement("docs-test")]
public class Test : CustomElementBase { }
Program.cs / MauiProgram.cs
...
builder.Services.AddBlazorWebComponents(r =>
{
r.Register<Test>("my-element");
});
...
Rendered output
<my-element>
<p>Hello, world!</p>
</my-element>
Register All Custom Elements
The RegisterAll
method will register all custom elements in a given assembly
that have not already been registered.
Test.razor
@inherits CustomElementBase
<p>Hello, world!</p>
Example.razor.cs
namespace Example;
[CustomElement("docs-test")]
public class Test : CustomElementBase { }
Program.cs / MauiProgram.cs
...
builder.Services.AddBlazorWebComponents(r =>
{
r.RegisterAll(Assembly.GetExecutingAssembly());
});
...
Rendered output
<docs-test>
<p>Hello, world!</p>
</docs-test>
Basic WebComponent
Test.razor
@inherits WebComponentBase
<p>Hello, world!</p>
Example.razor.cs
namespace Example;
[custom-element("docs-test")]
public class Test : WebComponentBase { }
Rendered output
<docs-test>
#shadow-root (open)
<p>Hello, world!</p>
</docs-test>
Shadow Root Mode
Test.razor
@inherits WebComponentBase
<p>Hello, world!</p>
Example.razor.cs
namespace Example;
[custom-element("docs-test")]
public class Test : WebComponentBase
{
public override ShadowRootMode ShadowRootMode => ShadowRootMode.Closed;
}
Rendered output
<docs-test>
#shadow-root (closed)
<p>Hello, world!</p>
</docs-test>
Web Component Styling
Test.razor
@inherits WebComponentBase
<p>Hello, world!</p>
Example.razor.cs
namespace Example;
[custom-element("docs-test")]
public class Test : WebComponentBase
{
public override ShadowRootMode ShadowRootMode => ShadowRootMode.Closed;
}
Example.razor.css
p {
color: red;
}
Rendered output
<docs-test>
#shadow-root (open)
<style>
p {
color: red;
}
</style>
<p>Hello, world!</p>
</docs-test>
CSS Selectors
Test.razor
@inherits WebComponentBase
Hello, world!
Example.razor.cs
namespace Example;
[custom-element("docs-test")]
public class Test : WebComponentBase { }
Index.razor
<Test />
Index.razor.css**
@namespace ce 'example';
[ce|test] {
border: 1px solid black;
}
<small style="font-size: 70%; float: right">Special thanks to Poor Egg Productions for the icon!</small>
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- Microsoft.CodeAnalysis.CSharp.Workspaces (>= 4.4.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Initial release of Ostomachion.Blazor.WebComponents.Generators