Rich text
The Portal uses the Lexical library
for rich text input, exposed through the
<koala-rich-text-editor>
tag helper. Used for quote & transaction notes (add + edit, in full-page and side tray contexts) and the
terms-of-engagement / partner-terms editors. The editor JS is bundled by esbuild from
Assets/note-editor.js
into /js/note-editor.js
and binds to any container with the data-note-editor attribute the tag helper emits.
Tag helper
Use <koala-rich-text-editor>
with an input-id (required) — the tag helper renders the toolbar,
contenteditable area, and hidden input that holds the serialised HTML for form submit.
| Attribute | Type | Description |
|---|---|---|
input-id |
string (required) | Id of the hidden input that holds the serialised content. |
input-name |
string | Form field name. Defaults to Input.Content. |
value |
string | Initial editor value (HTML). Defaults to empty. |
fill-height |
bool | Stretch to fill the parent flex container (used in side trays). Defaults to false (fixed min/max height). |
<!-- Add note (empty editor) -->
<koala-rich-text-editor input-id="add-note-content" />
<!-- Edit note (pre-fill from page model) -->
<koala-rich-text-editor input-id="edit-note-content"
value="@(Model.Input.Content ?? string.Empty)" />
<!-- Side-tray editor (fills remaining vertical space) -->
<koala-rich-text-editor input-id="modal-note-content" fill-height="true" />
<!-- Custom form-field name (terms editors) -->
<koala-rich-text-editor input-id="edit-terms-content"
input-name="TermsContent"
fill-height="true" />
<!-- Bundled editor JS is loaded once in _Layout.cshtml -->
<script src="/js/note-editor.js"></script>
Editor appearance
The editor has a sticky toolbar with formatting buttons, a content area with custom typography styles,
and full dark mode support. File uploads are disabled via a
trix-file-accept event listener.
This is an example of rich text content with various formatting options.
The editor supports:
- Bold, italic, and strikethrough text
- Links to external URLs
- Headings and blockquotes
- Bullet and numbered lists
Custom toolbar styling
The _TrixEditor partial
injects custom CSS that overrides the default Trix toolbar to match the app's design. Key customisations include
sticky toolbar positioning, uniform button sizing, hidden file upload tools, and responsive button visibility on mobile.
<!-- Key toolbar overrides in _TrixEditor partial -->
trix-toolbar {
position: sticky;
top: 0;
z-index: 1;
background: white;
border-bottom: 1px solid rgb(209 213 219);
}
trix-toolbar .trix-button {
border: none !important;
border-left: 1px solid rgb(209 213 219) !important;
height: 2.5rem !important;
width: 2.5rem !important;
}
trix-toolbar .trix-button-group--file-tools {
display: none !important;
}
/* Dark mode */
.dark trix-toolbar {
background: rgb(31 41 55);
border-bottom-color: rgb(75 85 99);
}
.dark trix-toolbar .trix-button {
filter: invert(0.8);
}
/* Hide less-used buttons on mobile */
@media (max-width: 639px) {
trix-toolbar .trix-button--icon-strike,
trix-toolbar .trix-button--icon-heading-1,
trix-toolbar .trix-button--icon-code { display: none !important; }
}
Side tray usage
The Trix editor is used in the "Add note" side tray for transactions. The form uses
x-target="side-tray-content"
for AJAX submission, with the submit button in the fixed tray footer linked via
form="add-note-form".
The <partial name="_TrixEditor"/>
is included inside the tray content so it loads with the AJAX response.
<div id="side-tray-content" class="flex-1 flex flex-col min-h-0">
<div class="shrink-0 flex items-center justify-between px-6 sm:px-8 py-4">
<h2 class="text-xl font-semibold text-gray-900 dark:text-white">Add note</h2>
<button type="button" x-on:click="$dispatch('close-side-tray')" ...>...</button>
</div>
<div class="flex-1 overflow-y-auto px-6 sm:px-8 py-6">
<form id="add-note-form" method="post" x-target="side-tray-content">
<input id="modal-note-content" type="hidden" name="NoteContent"/>
<div class="border border-gray-300 dark:border-gray-600 rounded-lg overflow-hidden">
<trix-editor id="modal-trix-editor"
class="trix-content"
input="modal-note-content"
placeholder="Write your note...">
</trix-editor>
</div>
<span asp-validation-for="NoteContent" class="mt-2 block"></span>
</form>
</div>
<div class="shrink-0 border-t border-gray-200 dark:border-gray-700 px-6 sm:px-8 py-4 flex justify-end">
<button type="submit" form="add-note-form" koala-loading koala-btn="Primary">
Add note
</button>
</div>
<partial name="_TrixEditor"/>
</div>
Content rendering
Stored HTML content is rendered read-only using the
trix-content CSS class
for consistent typography, or within a
prose container.
Both have matching dark mode styles defined in the partial.
Meeting notes
Discussed the following items with the client:
- Property chain confirmed - no issues
- Mortgage offer valid until 15 April 2026
- Local authority search results expected next week
"Client confirmed they are happy to proceed at the agreed price."