Build a rich text editing experience
Integrate the RichTagger editor, synchronize a form field, and understand the trust boundary around HTML.
Here's what you'll be able to do.
- Mount and configure the existing RichTaggerEditor
- Synchronize editor content with an MVC form
- Distinguish editor formatting from safe HTML rendering
Complete Razor and forms. Download rich-tagger.js and rich-tagger.css from Example projects. This feature is an optional extension, not part of TaskBoard’s plain-text notes baseline.
Understand the idea
A rich text editor provides a friendly way to create HTML. It does not make that HTML trustworthy. The browser, hidden form fields, and posted content are all under user control. Treat the editing experience and the server’s content policy as separate concerns.
RichTagger is the editor already included in Tutor. You can try its formatting controls below and inspect the resulting markup. The demonstration displays generated HTML as text; it does not execute arbitrary pasted HTML in a separate preview.
Choose your environment
Open TaskBoard.csproj from the example download. Install the ASP.NET and web development workload and a Visual Studio release supporting .NET 10. Select the TaskBoard launch profile and press F5. Use Solution Explorer to find the files named below.
Install the .NET 10 SDK and C# Dev Kit. Open the TaskBoard folder in VS Code. Run dotnet restore, then dotnet run in the integrated terminal. Browse http://localhost:5300. Open files with Ctrl+P (Cmd+P on macOS).
Add the editor assets
Place the JavaScript and stylesheet under wwwroot, then reference them from the view’s Scripts and Styles sections. A container gives the editor a place to render. A hidden field gives MVC a named form value to bind.
The sample below assumes an optional input property named BodyHtml on a dedicated article input model. Do not replace TaskBoard’s encoded plain-text Notes with raw HTML without designing storage and sanitization first.
<link rel="stylesheet" href="~/css/rich-tagger.css" />
<form method="post" id="article-form">
@Html.AntiForgeryToken()
<div id="article-editor"></div>
<input type="hidden" name="BodyHtml" id="body-html" />
<button type="submit">Save draft</button>
</form>
<script src="~/js/rich-tagger.js"></script>Initialize the actual editor API
The class in the supplied file is RichTaggerEditor. It takes a container id without a leading #. Its public content methods are getContent and setContent. Use the API that exists in this implementation rather than assuming it matches another editor library.
Initialize only after both the script and container exist. For a normal Razor page, putting initialization after the script in the Scripts section satisfies that ordering. Start with a small toolbar, then add controls only when your content policy supports them.
const editor = new RichTaggerEditor("article-editor", {
toolbar: ["bold", "italic", "underline", "unorderedlist", "orderedlist"]
});
editor.setContent("<p>Write your first paragraph.</p>");
document.getElementById("article-form").addEventListener("submit", () => {
document.getElementById("body-html").value = editor.getContent();
});The starter text above is a trusted constant. Do not concatenate untrusted stored HTML into an inline script.
Separate storage from rendering
A hidden field synchronizes state; it provides no security. Validate the request size and accepted content on the server. If your product stores rich HTML, use a maintained server-side HTML parser and allowlist sanitizer configured for your supported tags, attributes, and URL schemes.
The included editor’s sanitizeContent method uses regular expressions and is not a production security boundary. Script tags are only one way HTML can execute. Event attributes, dangerous URLs, SVG, malformed markup, and browser parsing differences all matter. Do not call Html.Raw on posted content based on that helper.
const output = document.getElementById("html-output");
output.textContent = editor.getContent();
// textContent displays markup as data.
// It does not parse it as a new HTML document.Keep a graceful editing workflow
Make save behavior explicit: synchronize at submission, return validation errors to the same page, and preserve the draft when a save fails. For stored content, pass data to JavaScript through safe serialization rather than hand-written quoting.
Test keyboard access, empty content, pasted formatting, and repeated submissions. An editor can visually look empty while containing wrapper tags. Define what “empty article” means after your chosen normalization policy. Keep plain-text fields plain unless rich formatting solves a real need.
1. Load assets and create the editor once.
2. Synchronize the hidden field before form submission.
3. Validate size and content on the server.
4. Apply an explicit server-side HTML policy.
5. Render only content that passed that policy.
6. Test keyboard use, pasting, and failed saves.Try the RichTagger editor
Edit the content below. The HTML panel shows the editor output as text; it is never executed.
Generated HTML
Make it your own.
Use the live editor to make a heading and a list. Inspect the generated HTML. Then explain why changing the hidden BodyHtml field in developer tools would bypass any editor-only restrictions.
See the solution & reasoning
The form submits whatever value is in its named field. A user can change that value or send a custom HTTP request without using the editor at all. Server-side policy must therefore validate the received content independently. The demo’s text output remains safe to inspect because it uses textContent.
When something doesn't work
“RichTaggerEditor is not defined” means the script did not load or ran after initialization. Check the asset URL and script order.
An empty posted value often means the hidden field lacks a name, sits outside the form, or was not synchronized before submission.
Do not mistake removal of script tags for comprehensive sanitization. Keep the original plain-text TaskBoard notes until a real server-side rich-content policy is implemented.
Does an editor toolbar make submitted HTML safe to render?
That's another skill in your toolkit.
Your progress is saved in this browser. Sign in to save completion to your account.