{"id":37056461,"url":"https://github.com/ostomachion/blazor.webcomponents","last_synced_at":"2026-01-14T06:22:41.302Z","repository":{"id":76443450,"uuid":"602308023","full_name":"ostomachion/blazor.webcomponents","owner":"ostomachion","description":"A simple library that allows Blazor components to be rendered as real standards-based Web Components using custom elements, shadow DOM, and HTML templates.","archived":false,"fork":false,"pushed_at":"2023-11-14T20:47:37.000Z","size":429,"stargazers_count":5,"open_issues_count":9,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-30T23:32:06.595Z","etag":null,"topics":["blazor","customelements","htmltemplate","shadowdom","webcomponents"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ostomachion.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-02-15T23:42:48.000Z","updated_at":"2024-10-08T07:50:33.000Z","dependencies_parsed_at":null,"dependency_job_id":"bf4cf99d-94c9-49c6-a869-2e4477fd06ef","html_url":"https://github.com/ostomachion/blazor.webcomponents","commit_stats":null,"previous_names":["ostomachion/blazor.webcomponents"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ostomachion/blazor.webcomponents","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ostomachion%2Fblazor.webcomponents","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ostomachion%2Fblazor.webcomponents/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ostomachion%2Fblazor.webcomponents/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ostomachion%2Fblazor.webcomponents/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ostomachion","download_url":"https://codeload.github.com/ostomachion/blazor.webcomponents/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ostomachion%2Fblazor.webcomponents/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28412210,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T05:26:33.345Z","status":"ssl_error","status_checked_at":"2026-01-14T05:21:57.251Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blazor","customelements","htmltemplate","shadowdom","webcomponents"],"created_at":"2026-01-14T06:22:41.236Z","updated_at":"2026-01-14T06:22:41.293Z","avatar_url":"https://github.com/ostomachion.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"﻿# BlazorWebComponents\n\nA simple library that allows Blazor components to be rendered as real\nstandards-based Web Components using custom elements, shadow DOM, and HTML\ntemplates.\n\nStill in development, but mostly tested and functional for Blazor WebAssembly\nprojects.\n\n## TL;DR\n\n1. Follow the [installation](#installation) and [setup](#setup) sections.\n2. Modify the call to `AddBlazorWebComponents` to the following:\n    ```csharp\n    builder.Services.AddBlazorWebComponents(r =\u003e r.RegisterAll(Assembly.GetExecutingAssembly())});\n    ```\n3. Add a new Razor Component to your project:\n    \n    *MyComponent.razor*\n    ```razor\n    @inherits CustomElementBase\n    \u003cp class=\"shadow\"\u003eShadow: @Value\u003c/p\u003e\n    \u003cp class=\"light\"\u003eLight: \u003cSlot Name=\"value\" For=\"Value\"\u003emissing value\u003c/Slot\u003e\u003c/p\u003e\n    ```\n\n    *MyComponent.razor.cs*\n    ```csharp\n    namespace My.Namespace;\n\n    [CustomElement(\"my-component\")]\n    public class MyComponent : WebComponent\n    {\n        [Parameter]\n        [EditorRequired]\n        public string Value { get; set; } = default!;\n    }\n    ```\n\n    *MyComponent.razor.css*\n    ```css\n    .shadow { background: lightgray; }\n    .light { background: lightyellow; }\n    ```\n\n4. Add the component to the main page.\n\n    ```razor\n    \u003cMyComponent Value=\"Hello, world!\" /\u003e\n    ```\n\nThat's it! You've got a full standards-based web component from Blazor!\n\n*Rendered output*\n```html\n\u003cmy-component\u003e\n    #shadowroot (open)\n      \u003cstyle\u003e\n        .shadow { background: lightgray; }\n        .light { background: lightyellow; }\n      \u003c/style\u003e\n      \u003cp class=\"shadow\"\u003eShadow: Hello, world!\u003c/p\u003e\n      \u003cp class=\"light\"\u003eLight: \u003cslot name=\"value\"\u003emissing value\u003c/slot\u003e\u003c/p\u003e\n\n    \u003cspan slot=\"value\"\u003eHello, world!\u003c/span\u003e\n\u003c/my-component\u003e\n```\n\n## Installation\n\n```\ndotnet add package Ostomachion.Blazor.WebComponents\n```\n\n## Setup\n\nFirst, follow the installation and setup instructions for\n[Ostomachion.Blazor.ShadowDom](https://github.com/ostomachion/blazor.shadowdom/blob/main/README.md).\n(This will be included automatically in a future release.)\n\n### WebAssembly\n\nIn `wwwroot/index.html`, add the following script:\n\n```html\n\u003cscript src=\"_content/Ostomachion.Blazor.WebComponents/blazor-web-components.js\"\u003e\u003c/script\u003e\n```\n\nIn `Program.cs`, add the following lines:\n\n```csharp\nbuilder.RootComponents.Add\u003cCustomElementRegistrarComponent\u003e(\"head::after\");\nbuilder.Services.AddBlazorWebComponents();\n```\n\n### Server\n\n**Note:** Blazor Web Components has not yet been thoroughly tested with Blazor\nserver.\n\nIn `Pages/_Host.html`, add the following script:\n\n```html\n\u003cscript src=\"_content/Ostomachion.Blazor.WebComponents/blazor-web-components.js\"\u003e\u003c/script\u003e\n```\n\nIn `Program.cs`, add the following lines:\n\n```csharp\nbuilder.Services.AddBlazorWebComponents();\n```\n\nIn `Pages/_Host.cs` add the following line to the end of the `head` element:\n\n```razor\n\u003ccomponent type=\"typeof(CustomElementRegistrarComponent)\" render-mode=\"ServerPrerendered\" /\u003e\n```\n\n### MAUI\n\n**Note:** Blazor Web Components has not yet been thoroughly tested with\nMAUI/Blazor WebView.\n\nIn `wwwroot/index.html`, add the following script:\n\n```html\n\u003cscript src=\"_content/Ostomachion.Blazor.WebComponents/blazor-web-components.js\"\u003e\u003c/script\u003e\n```\n\nIn `MauiProgram.cs` add the following line:\n\n```csharp\nbuilder.Services.AddBlazorWebComponents();\n```\n\nIn `MainPage.xaml`, in the `BlazorWebView.RootComponents` element, add the\nfollowing line:\n\n```xml\n\u003cRootComponent Selector=\"head::after\" ComponentType=\"{x:Type Ostomachion.BlazorWebComponents.CustomElementRegistrarComponent}\" /\u003e\n```\n\n## Custom Elements\n\n### Creating a Custom Element Component\n\n**Note:** Custom elements must be [registered](#registering-custom-elements)\nbefore they can be rendered on a page.\n\n**Important:** Please read and understand the [notes on technical limitations](#notes-on-technical-limitations).\n\nAny component class that inherits `Ostomachion.WebComponents.CustomElementBase`\nwill be rendered inside a [custom element](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements).\n\nBy default, custom elements are rendered as **autonomous custom elements** with\nan identifier generated from the component's class and namespace.\n[(Example)](#basic-custom-element)\n\nThe default identifier can be specified using a `CustomElementAtrribute`.\n[(Example)](#custom-default-identifier)\n\nA **customized built-in element** can be created using a `CustomElementAttribute`.\n[(Example)](#customized-built-in-element)\n\nIf a reference to the generated custom element is stored in the `Host` property\nof the component.\n\nAttributes on the generated custom element can be set using the `HostAttributes`\nproperty of the component. [(Example)](#adding-host-attribute)\n\n### Registering Custom Elements\n\nBefore a custom element component can be rendered on a page, it must be\nregistered by passing an action to the call to `AddBlazorWebComponents`.\n[(Example)](#basic-registration)\n\nTo avoid identifier collisions and to allow more customization, an identifier\ncan be registered with the component which will override any default identifier\ndefined by the component itself.\n[(Example)](#identifier-registration)\n\nFor convenience, all custom elements in an assembly can be registered at once\nusing their default identifiers by calling `RegisterAll`. Any custom elements that\nhave already been registered will be skipped by `RegisterAll`.\n[(Example)](#register-all-custom-elements)\n\n## Web Components\n\n**Web Components** are extensions of custom elements with many extra features.\nEverything in the [Custom Elements](#custom-elements) section applies to web\ncomponents including [registration](#registering-custom-elements).\n\nIn addition to being wrapped in a [custom element](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements),\nweb components are also rendered in a [shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM)\nand make use of [templates and slots](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_templates_and_slots).\n\n### Creating a Web Component\n\nAny component class that inherits `Ostomachion.WebComponents.WebComponentBase`\nwill be rendered inside a shadow DOM attached to custom element.\n[(Example)](#basic-web-component)\n\nBy default, an open shadow root is attached to the host element. The shadow root\nmode can be specified by overriding the `ShadowRootMode` property on the\ncomponent.\n[(Example)](#shadow-root-mode)\n\nAny CSS file associated with the class will be automatically encapsulated in the\nshadow root.\n[(Example)](#web-component-styling)\n\n### Slots\n\nBy default, the content of a web component is rendered in the shadow DOM and\ngenerally encapsulated from CSS and JavaScript outside the component.\n\nTODO\n\n## Notes on CSS\n\nSince the host element name of a custom element component can vary, CSS selectors\nbecome fragile. As a workaround, this library adds custom namespaced elements to\ncustom elements. The attribute name is equal to the class name in lowercase with\na namespace equal to the namespace of the class in lowercase. This not only\nprovides a unique name for each component, it more closely matches the source\nRazor file.\n[(Example)](#css-selectors)\n\n## ⚠️ Notes on Technical Limitations ⚠️\n\n**Be aware of the following limitations:**\n- A component that inherits either `CustomElementBase` or `WebComponentBase`\n  **MUST** declare the base class in the `.cs` file (*and* the `.razor` file if one\n  exists).\n- A `CustomElementAttribute` **MUST** be applied to the class in the `.cs` file\n  and **not** in the `.razor` file.\n- Any properties with a `SlotAttribute` **MUST** be defined in the `.cs` file and\n  not in the `.razor` file.\n\nAdding `\u003cUseRazorSourceGenerator\u003efalse\u003c/UseRazorSourceGenerator\u003e` to the `.csproj`\nshould in theory fix these limitations, but this is not a priority to support.\nPlease report any issue if you need this feature.\n\n**Explanation:** Some of the functionality of this library is implemented as a C#\nsource generator. Unfortunately, there is currently no great way to get source\ngenerators to work will with Razor files. This means that the Blazor Web Component\nsource generator will not work properly if you add certain features to the\n`.razor` side of a component rather than the `.cs` side.\n\n## Examples\n\n### Basic Custom Element\n\n*Test.razor*\n```razor {data-filename=\"Test.razor\"}\n@inherits CustomElementBase\n\u003cp\u003eHello, world!\u003c/p\u003e\n```\n\n*Example.razor.cs*\n```csharp\nnamespace Example;\n\npublic class Test : CustomElementBase { }\n```\n\n*Rendered output*\n```html\n\u003cexample-customelementbase\u003e\n  \u003cp\u003eHello, world!\u003c/p\u003e\n\u003c/example-customelementbase\u003e\n```\n\n### Custom Default Identifier\n\nThe default identifier can be changed by adding a `CustomElementAttribute` to the\nclass.\n\n*Test.razor*\n```razor\n@inherits CustomElementBase\n\u003cp\u003eHello, world!\u003c/p\u003e\n```\n\n*Example.razor.cs*\n```csharp\nnamespace Example;\n\n[CustomElement(\"docs-test\")]\npublic class Test : CustomElementBase { }\n```\n\n*Rendered output*\n```html\n\u003cdocs-test\u003e\n  \u003cp\u003eHello, world!\u003c/p\u003e\n\u003c/docs-test\u003e\n```\n\n### Customized Built-In Element\n\nA **customized built-in element** can be created by adding a\n`CustomElementAttribute` to the class.\n\n*Test.razor*\n```razor\n@inherits CustomElementBase\n\u003cp\u003eHello, world!\u003c/p\u003e\n```\n\n*Example.razor.cs*\n```csharp\nnamespace Example;\n\n[CustomElement(\"docs-test\", Extends = \"div\")]\npublic class Test : CustomElementBase { }\n```\n\n*Rendered output*\n```html\n\u003cdiv is=\"docs-test\"\u003e\n  \u003cp\u003eHello, world!\u003c/p\u003e\n\u003c/div\u003e\n```\n\n### Adding Host Attributes\n\nAttributes can be set on the generated custom element using the `HostAttributes`\nproperty.\n\n*Test.razor*\n```razor\n@inherits CustomElementBase\n@HostAttributes[\"id\"] = \"host\"\n\u003cp\u003eHello, world!\u003c/p\u003e\n```\n\n*Example.razor.cs*\n```csharp\nnamespace Example;\n\n[CustomElement(\"docs-test\")]\npublic class Test : CustomElementBase { }\n```\n\n*Rendered output*\n```html\n\u003cdocs-test id=\"host\"\u003e\n  \u003cp\u003eHello, world!\u003c/p\u003e\n\u003c/docs-test\u003e\n```\n\n### Basic Registration\n\nA custom element must be registered before it can be rendered on a page.\n\n*Test.razor*\n```razor\n@inherits CustomElementBase\n\u003cp\u003eHello, world!\u003c/p\u003e\n```\n\n*Example.razor.cs*\n```csharp\nnamespace Example;\n\n[CustomElement(\"docs-test\")]\npublic class Test : CustomElementBase { }\n```\n\n*Program.cs / MauiProgram.cs*\n```csharp\n...\nbuilder.Services.AddBlazorWebComponents(r =\u003e\n{\n    r.Register\u003cTest\u003e();\n});\n...\n```\n\n*Rendered output*\n```html\n\u003cdocs-test\u003e\n  \u003cp\u003eHello, world!\u003c/p\u003e\n\u003c/docs-test\u003e\n```\n\n### Identifier Registration\n\nThe default identifier of a custom element can be overridden at registration.\n\n*Test.razor*\n```razor\n@inherits CustomElementBase\n\u003cp\u003eHello, world!\u003c/p\u003e\n```\n\n*Example.razor.cs*\n```csharp\nnamespace Example;\n\n[CustomElement(\"docs-test\")]\npublic class Test : CustomElementBase { }\n```\n\n*Program.cs / MauiProgram.cs*\n```csharp\n...\nbuilder.Services.AddBlazorWebComponents(r =\u003e\n{\n    r.Register\u003cTest\u003e(\"my-element\");\n});\n...\n```\n\n*Rendered output*\n```html\n\u003cmy-element\u003e\n  \u003cp\u003eHello, world!\u003c/p\u003e\n\u003c/my-element\u003e\n```\n\n### Register All Custom Elements\n\nThe `RegisterAll` method will register all custom elements in a given assembly\nthat have not already been registered.\n\n*Test.razor*\n```razor\n@inherits CustomElementBase\n\u003cp\u003eHello, world!\u003c/p\u003e\n```\n\n*Example.razor.cs*\n```csharp\nnamespace Example;\n\n[CustomElement(\"docs-test\")]\npublic class Test : CustomElementBase { }\n```\n\n*Program.cs / MauiProgram.cs*\n```csharp\n...\nbuilder.Services.AddBlazorWebComponents(r =\u003e\n{\n    r.RegisterAll(Assembly.GetExecutingAssembly());\n});\n...\n```\n\n*Rendered output*\n```html\n\u003cdocs-test\u003e\n  \u003cp\u003eHello, world!\u003c/p\u003e\n\u003c/docs-test\u003e\n```\n\n### Basic WebComponent\n\n*Test.razor*\n```razor\n@inherits WebComponentBase\n\u003cp\u003eHello, world!\u003c/p\u003e\n```\n\n*Example.razor.cs*\n```csharp\nnamespace Example;\n\n[custom-element(\"docs-test\")]\npublic class Test : WebComponentBase { }\n```\n\n*Rendered output*\n```html\n\u003cdocs-test\u003e\n  #shadow-root (open)\n    \u003cp\u003eHello, world!\u003c/p\u003e\n\n\u003c/docs-test\u003e\n```\n\n### Shadow Root Mode\n\n*Test.razor*\n```razor\n@inherits WebComponentBase\n\u003cp\u003eHello, world!\u003c/p\u003e\n```\n\n*Example.razor.cs*\n```csharp\nnamespace Example;\n\n[custom-element(\"docs-test\")]\npublic class Test : WebComponentBase\n{\n    public override ShadowRootMode ShadowRootMode =\u003e ShadowRootMode.Closed;\n}\n```\n\n*Rendered output*\n```html\n\u003cdocs-test\u003e\n  #shadow-root (closed)\n    \u003cp\u003eHello, world!\u003c/p\u003e\n\n\u003c/docs-test\u003e\n```\n\n### Web Component Styling\n\n*Test.razor*\n```razor\n@inherits WebComponentBase\n\u003cp\u003eHello, world!\u003c/p\u003e\n```\n\n*Example.razor.cs*\n```csharp\nnamespace Example;\n\n[custom-element(\"docs-test\")]\npublic class Test : WebComponentBase\n{\n    public override ShadowRootMode ShadowRootMode =\u003e ShadowRootMode.Closed;\n}\n```\n\n*Example.razor.css*\n```css\np {\n    color: red;\n}\n```\n\n*Rendered output*\n```html\n\u003cdocs-test\u003e\n  #shadow-root (open)\n    \u003cstyle\u003e\n        p {\n            color: red;\n        }\n    \u003c/style\u003e\n    \u003cp\u003eHello, world!\u003c/p\u003e\n\n\u003c/docs-test\u003e\n```\n\n### CSS Selectors\n\n*Test.razor*\n```razor\n@inherits WebComponentBase\nHello, world!\n```\n\n*Example.razor.cs*\n```csharp\nnamespace Example;\n\n[custom-element(\"docs-test\")]\npublic class Test : WebComponentBase { }\n```\n\n*Index.razor*\n```razor\n\u003cTest /\u003e\n```\n\n*Index.razor.css***\n```css\n@namespace ce 'example';\n\n[ce|test] {\n    border: 1px solid black;\n}\n```\n\n---\n\n\u003csmall style=\"font-size: 70%; float: right\"\u003e*Special thanks to [Poor Egg Productions](https://pooregg.productions) for the icon!*\u003c/small\u003e","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fostomachion%2Fblazor.webcomponents","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fostomachion%2Fblazor.webcomponents","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fostomachion%2Fblazor.webcomponents/lists"}