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