Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

HtmlEditor Written in Blazor

0.00/5 (No votes)
28 Apr 2020 1  
A HtmlEditor written in Blazor based on AngleSharp
Although you can use an HTML-editor, like TinyMC, in a Blazor-project (by wrapping the JavaScript code), it is recommended to use native Blazor component instead. The code is intended to show how you can implement a HTML editor in Blazor. The primary goal is to investigate the challenges, not to create a full-blown editor, tested in every browser.

Introduction

The setup is as follows: the project HTMBuilder is a class library with core editor functionality. That is pure .NET, without UI, with an accompanying test project.

The HTMLEditableContent project is a Blazor component with a ContentEditable div. It calls HtmlBuilder to render HTML in a contentEditable div.

BlazorHtmlEditor is a Blazor component built around HtmlEditableContent. The UI shell is programmed with MatBlazor (Material Design for Blazor).

This design was chosen because you can replace each component with your own component. If you don't want a Material Design editor, you can build your own UI shell. If you only want the logic, then the HTMLBuilder is enough.

The code is completely based on AngleSharp. A .NET library representing HTML-documents.

Challenges

The biggest challenge is the combination of Blazor binding combined with a ContentEditable HTML element. At first, I used binding. The HTML generated by AngleSharp was bound to the HTML element via a MarkUpString.

The problem is that the browser implements the changes in a contenteditable element in a MutationObserver-like manner. After Blazor, via binding, has updated the HTML, the browser sees that the element has been changed and then also starts working. The only way to work around that is not to use Blazor binding, but to update the HTML element via JavaScript via Interop.

Another problem was that the Editor Blazor component and the HtmlEditableContent Blazor component have to communicate with each other. For example, the Editor wants to show changes in the cursor position. If you implement this link via Parameter bindings, Blazor will consider any cursor position change as a Parameter change, including rendering. You don't want that at all.

This was solved by putting a shared class between the Editor and HtmlEditableContent component. The editor registers an editor interface in a static dictionary and the EditableContent registers an Htmlbuilder interface in another static dictionary. The dictionary will be shared between the two components. Both the Editor and the Content component have an ID property (Guid) and it is shared (via a parameter). Because they have the same key, they can request each other's interfaces in the shared libraries, without any renderings taking place. It is not ideal, but it works.

A Closer Look at the HtmlEditableContent

If a user changes the cursor or selection in the browser, these position changes are passed via JavaScript to the Blazor component. Content changes are not immediately communicated.

If the .NET side has to perform an operation, it asks the browser for the positions and the content (innerHTML). Then, AngleSharp parses the document and performs the operation. The result is new HTML content. Via JavaScript, the old content is replaced by the new and the cursor selection positions are restored.
This setup limits the number of interactions between the JavaScript and the Blazor side. The exceptions to this are position changes.

Using the Code

Warning: All projects are experimental. The intention is only to demonstrate how to build an HtmlEditor in Blazor. For example, I haven't taken the time to fully familiarize myself with AngleSharp, nor did I take the time to program a fully featured HTML-editor. Also, I have not tested everything in all browsers. That takes a lot more time. My main concern is the challenges encountered in building a Blazor HTML Editor.

The code is very easy to use.

//
<BlazorHtmlEditor.HtmlEditor BlockStylings="@BlockStylings"></BlazorHtmlEditor.HtmlEditor>
//

In the BlockStyling parameters, you pass styles like H1 and H2. There is also the possibility to pass Colors and FontStyling. The HtmlEditors use defaults if you don't provide them.

What Now

Study the code, play with it yourself, make improvements and extensions, make suggestions, improve the UI and so on. Despite all the difficulties, it remains a pleasure to work with Blazor.

Installation

Unzip the zip file. Execute:

dotnet restore

Change active directory to HtmlEditablContent. Run:

npm install

Run:

npm run build:debug

History

  • 27th April, 2020: Initial version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here