Online Rich Text Editor: Keep the Document Structure Separate from Its Plain Text

You bold one word in an announcement, then copy its plain text and wonder where the emphasis went. Or a pasted paragraph brings in fonts and links that the toolbar never offered.

An online rich text editor needs a document-format policy and clearly labeled output representations.

Use the original announcement below to inspect headings, emphasis, and a bullet list. The local HTML example embeds Quill 2.0.3 and provides the bounded formatting controls; verify selection and input behavior in the intended host. It is a bounded local editor, not a saved or collaborative editing service.

A small announcement editor
A small announcement editor
Open the full example ↗

Begin with a small structured announcement

The initial fixture contains:

Document part Text Intended structure
Title Studio work session One H2 heading
Paragraph Bring your draft. Ordinary paragraph
Item 1 Outline Bullet-list item
Item 2 Source notes Bullet-list item

Keep the fixture's actual words unchanged when testing formatting. Select only “draft” in the paragraph and apply Bold. The paragraph's plain text remains “Bring your draft.” Its formatted document now includes emphasis on that word. Toggle Bold off on the same selection; the word stays in place and loses that mark.

Use this as the first interaction test: formatting changes a mark, not the words. A button that deletes and reinserts the paragraph is not an acceptable substitute for applying a selection format.

Enforce the format policy beyond the toolbar

Allow only Bold, Italic, H2, and bullet lists. Quill's formats documentation distinguishes allowed document formats from visible toolbar controls. Hiding a toolbar button alone does not define what may exist in the document.

Check format values as well as names. Allow header level 2, not every value of the header attribute; allow bullet lists, not ordered or checklist variants. In the model validation, remove unsupported format attributes while preserving inserted text. A block cannot carry both a heading and a list format in this example; normalize such a conflict to an unformatted text block rather than silently choosing a meaning.

Disable links, images, video, fonts, colors, raw HTML import, and other embeds. Validate the actual document model after initial loading and changes, before producing an output representation. The allowlist defines this editor's scope; it is not a general HTML sanitizer.

Initialize the trusted fixture from its declared text and allowed model attributes. Keep that route separate from user paste so a convenient fixture loader does not become an arbitrary HTML-import feature.

Label three representations of the same document

The Quill API distinguishes plain text from formatted Delta contents and an HTML representation. Use three visible areas:

Area What it represents
Rich document The editable heading, paragraph, emphasis, and list
Plain text Words and line breaks without formatting marks
Semantic HTML source A textual representation carrying supported structure

The implementation can obtain plain text with getText, model contents with getContents, and the HTML representation with getSemanticHTML. The acceptance test is semantic: one H2, one ordinary paragraph, two bullet items, and the selected emphasis. Do not promise an exact serializer wrapper string or assume a DOM snapshot equals the intended semantic export.

Show output strings in labeled read-only text fields or with textContent. The source-inspection area displays HTML characters; it does not execute arbitrary HTML as a preview. Editing the rich document should update those outputs through the actual change path. Mark old outputs stale until recomputation succeeds, including after a format-only change. Updated output is not an autosave record.

Paste text under an explicit rule

This example accepts clipboard plain text only. Preserve the clipboard's text characters, replace any selected range, and insert that text without adopting its external styling. Existing text outside the selection stays in place. Unsupported images or other clipboard-only media are not imported.

Quill's clipboard documentation explains that HTML interpretation can differ from input HTML and identifies precautions around arbitrary HTML insertion. This design does not pass user input to dangerouslyPasteHTML. Merely limiting formats does not make every possible HTML-import path safe.

Test a typed literal such as <script>: it should remain visible text in the editor and be escaped in the HTML representation. That is an acceptance requirement, not a claim that injection or network tests have already passed.

If plain-text clipboard data is unavailable, show a message and leave the document unchanged. Do not silently fall back to interpreting the clipboard's HTML. Ordinary typing remains available.

Make selection, empty state, and Reset inspectable

Native format buttons need labels and a reliable selection route. Preserve and restore the intended selection when the toolbar receives focus, so Bold targets “draft,” not a different word or the next character typed. A missing selection requires a clear state rather than a guessed text range.

Quill retains a terminal newline even in an empty document. Treat that required blank line as empty content for this example, not one word or a composed announcement. Do not remove meaningful user line breaks merely to make an empty-state test pass.

Reset asks for confirmation before replacing the current document with the initial fixture. Cancel leaves the document and outputs unchanged; confirmation restores the title, paragraph, two bullets, and matching outputs. No separate saved copy is implied.

Declare the Quill JavaScript and styling dependency and its chosen loading method. If loading fails, show an unavailable-editor state with the fixture as readable text; do not render working-looking format buttons. This local example embeds its library code and styles; it still depends on Quill and needs browser and host checks.

Copyable editor prompt

Build an original HTML/CSS/JavaScript announcement editor with readable source and an acceptance-test report, using documented Quill 2.0.3. Declare JS/CSS dependency/loading/failure; no offline or self-contained guarantee. Do not copy source example text/code/layout.

Trusted initial fixture: H2 'Studio work session'; paragraph 'Bring your draft.'; two bullet items 'Outline' and 'Source notes'. Allowed marks bold/italic, header value 2 only, list value 'bullet' only. Enforce names AND values in actual Delta/model before outputs; strip unsupported attributes without removing text. Header/list conflict becomes unformatted block. Disable links/embeds/fonts/colors/raw HTML import. Format allowlist is not a universal sanitizer.

Native labeled Bold/Italic/H2/Bullet controls preserve intended selection/focus. Select only 'draft', Bold: paragraph plain text unchanged; toggle off: same text, mark removed. Trusted fixture model initialization separate from user input; no homegrown execCommand engine.

Clipboard plain-text only: preserve text characters, replace selected range and insert without external styling; keep outside text. No available plain text -> message/no mutation, never HTML fallback. No dangerouslyPasteHTML for user data. Typed '<script>' stays literal and serialized escaped; actual security test required.

Three labeled areas: rich editable document, read-only plain text, read-only semantic HTML source. getText/getContents/getSemanticHTML represent distinct forms; inspect semantic output for one H2, a paragraph, two bullet items and the selected mark, not exact serializer wrappers. Display output via textContent/read-only text field, never execute arbitrary HTML preview. Actual text/format changes mark outputs stale until successful model-validation/recompute; no autosave.

Quill empty terminal newline means empty content, not one word; preserve other meaningful line breaks. Reset confirmation Cancel keeps all state; Confirm restores initial model and outputs. Optional Copy only on actual clipboard success, otherwise selectable-text fallback. Missing dependency shows readable fixture/unavailable status and disables editor controls.

Provide model/selection/paste/output/reset acceptance cases, keyboard/focus checks, actual article width and 360 px. Mark unexecuted dependency/runtime/security checks not_tested. Preserve native notes/source requirements; no DOCX/PDF conversion, cloud save, collaboration, publishing, persistence or host guarantee.

Optional use for prepared HTML

Keep the maintained native notes and editor source as the primary material. If you prepare a structured HTML version for NOS, its supplied product evidence supports HTML saving and rendering. Verify the library, selection controls, paste policy, and output fields in the actual workspace before treating the editor there as functional.

Explore NOS with prepared HTML, keeping the plain text and semantic source labeled separately so an output's missing marks are understood rather than mistaken for lost words.

Keep reading