cswork / libraryOpen practice workspace

Articles

Rich Text Editor Interview Questions: Selection, Composition, and Document State

Practice rich text editor interviews with document models, selection mapping, IME composition boundaries, paste normalization, and transaction history.

A rich text editor accepts English typing, then loses the caret when you toggle bold. Pasting formatted text corrupts its structure. Chinese input breaks because a render replaces the composing text halfway through candidate selection. The same implementation can pass a simple typing demonstration and still fail its editing contract.

Rich text editor interview questions become manageable when you separate four owners: the structured document, its selection, the browser's active composition, and the transaction history. Treat the editable DOM as a view and input surface, not the complete persistent model. Every edit needs a rule for transforming content and selection together.

Official platform and ProseMirror documentation support the cited mechanics. No candidate reports establish an employer's prompt format or frequency; the architecture choices below are original recommendations.

Why is contenteditable not a document model?

A document model describes the editor's supported structure independently of incidental DOM nodes. It can define paragraphs, text, marks, lists, and embedded objects, together with rules about which combinations are valid. The editable DOM presents that model and participates in native input, but browser-generated markup alone does not define the product's semantics.

The ProseMirror guide describes a schema-based document and state approach. For this original exercise, allow paragraphs, text, and bold marks, but no arbitrary embedded HTML. That deliberately small schema makes paste normalization and selection reasoning inspectable.

Saving innerHTML after every keystroke conflates persistence with rendering artifacts. Two equivalent documents may have different nested markup. A script or event-handler attribute from pasted content is also not a valid editing feature simply because the browser can display it. Define import and export rules separately from the live DOM.

In an interview, scope matters. Building a paragraph-only editor with correct input boundaries is more credible than claiming a complete word processor while leaving selection and composition unspecified. State which native behaviors you delegate and which edits your application owns.

What information does selection contain?

Selection is not merely a single caret index. A text selection has two endpoints and a direction; a collapsed selection places them together. Editors may also support node selections or other structures that do not fit one plain-text offset.

MDN's Selection API distinguishes anchor and focus. The anchor is not necessarily the earlier document position. A user selecting backward can produce the same highlighted range but a different direction, which affects later extension behavior.

For the original model, represent endpoints as block identity plus local text offset. Do not keep a raw DOM node as the durable selection: a render or normalization may replace that node. An adapter can convert the browser selection into model coordinates and resolve model coordinates back to the current view.

Also identify the coordinate system. JavaScript string offsets are not necessarily user-perceived character counts. Emoji, combining marks, and text split across nodes make naive “one character equals one offset” reasoning unsafe. If the simplified fixture uses UTF-16 offsets, label that scope and test grapheme-aware movement separately.

How does a transaction preserve selection?

A transaction is one logical state change with enough information to update document content, selection, and associated editor state. It may contain several low-level operations while still representing one user action, such as replacing selected text with pasted content.

In this original plain-text offset exercise, the document is abcd, with a caret at position 3, between c and d. Inserting XY at position 1 produces aXYbcd; the same logical caret should map to position 5. Leaving it at 3 would move it into the inserted text's neighborhood rather than preserving the intended location.

function mapInsertion(position, at, length, bias = 1) {
  if (position < at) return position;
  if (position > at) return position + length;
  return bias < 0 ? position : position + length;
}

This is only an insertion mapping, not a complete rich-document transform. Its boundary case is nevertheless valuable: a caret exactly at the insertion location needs an association policy. A remote insertion may keep the caret before the new text, while a local typed insertion usually leaves it after the inserted content.

Executed example evidence: Node.js v26.9.0 checks confirmed the four insertion-boundary cases, including both biases. The caret in abcd mapped from 3 to 5 in aXYbcd. A backward selection retained anchor/focus direction after insertion. An emoji fixture confirmed UTF-16 offsets rather than grapheme counts. These checks cover plain-text mapping, not native selection, a full document tree, or IME behavior.

Deletion adds another policy: positions inside the removed range must collapse to an appropriate surviving boundary. Structural edits can merge blocks or remove selected nodes. A mature editor mapping facility is preferable to accumulating unrelated offset patches in every toolbar handler.

Why does a toolbar make the caret disappear?

Clicking a formatting control can move browser focus away from the editing surface. If the command then asks the browser for the “current selection,” it may no longer retrieve the intended document range. The fix is a selection ownership policy, not repeatedly forcing focus without understanding the command.

Keep the last valid model selection in editor state. A formatting command applies to that selection, produces a transaction, and restores focus through the current view. If the document changed in the meantime, map or validate the stored selection rather than reusing stale DOM endpoints.

The command must also explain collapsed-selection behavior. Does toggling bold at a caret set stored marks for future input, or modify an existing range? These are distinct user intentions. An interview implementation should define both even if only one is in scope for the demonstration.

For accessibility, retain normal keyboard access to toolbar controls and make active formatting state understandable. Suppressing every pointer event to preserve focus can create a different usability problem. Test the actual focus path rather than prescribing one universal event trick.

What changes during IME composition?

Input method editors let users construct text through an intermediate composition session. The visible text may be provisional until the user commits a candidate. Treating every key as a finished character can destroy that session or turn candidate confirmation into an unrelated action.

MDN documents compositionstart, and the W3C Input Events specification describes composition-related input intentions. During the active session, avoid replacing the composing DOM subtree with a freshly rendered value on each update.

For this original state model, composition start establishes native input ownership. Provisional changes update the view through the editor's composition-aware input adapter. Composition completion reconciles the final text into the transaction model; the adapter must observe the supported environment's actual event sequence rather than assume one universal commit order. A toolbar or remote operation that would replace that same region needs a defined defer, map, or cancellation policy.

This is not a recommendation to ignore all state changes while composing. Status indicators, unrelated panels, and editor infrastructure can still update. The dangerous boundary is an operation that invalidates the native composing range or changes the semantics of its input while the browser owns it.

Is beforeinput enough to handle every edit?

The beforeinput documentation exposes editing intent before a browser modification, but warns that not every modification has a uniformly cancelable event. Actual behavior varies by input source and browser. Do not claim that one preventDefault() handler gives universal ownership of all editing.

Classify inputs instead. Typed insertion, paragraph insertion, deletion, paste, composition, autocorrect, and history actions can follow different paths. A browser adapter must reconcile observed changes when interception is not available, while preventing the application model and DOM from drifting into two independent truths.

An original failure trace is: composition begins, a candidate update arrives, a controlled render replaces the paragraph, the candidate commits against a lost native range, and the application inserts duplicated or misplaced text. A composition-aware editor library can manage much of this complexity; your answer should still identify which layer owns the session.

Synthetic dispatched events are useful for handler tests, but they do not reproduce a real operating-system IME. A browser test that types Latin letters is not evidence that Chinese or Japanese composition is correct. State that limitation explicitly.

What should happen when formatted content is pasted?

Treat paste as an import operation. Extract the supported content, sanitize untrusted markup, normalize it to the schema, and insert the resulting document fragment through one transaction. Map the selection to the insertion end according to the product's behavior.

For this article's small schema, a pasted heading can become a paragraph, supported bold marks can survive, and unsupported embedded objects can be removed or converted to a declared placeholder. Those are original product choices, not mandatory browser defaults. Explain them to the user if information is discarded.

Do not confuse schema validation with sanitization. A model can enforce paragraph structure while an unsafe renderer still injects an untrusted URL or HTML attribute. Conversely, sanitized markup may still violate the editor's allowed structure. Both boundaries need their own tests.

Plain-text paste should preserve intentional newlines under a defined rule. Pasting over a selection is a replacement, not an insertion followed by a separately undoable deletion. The transaction should describe the final content and selection as one logical action.

Where should undo and remote edits live?

History belongs to logical transactions, not arbitrary DOM snapshots captured every frame. Grouping may combine consecutive typing, while paste, formatting, and explicit structural commands can establish their own boundaries. Selection restoration is part of the expected undo experience, not a decorative afterthought.

Composition introduces a grouping question: should one committed word require several undo actions because it passed through candidate states? For this fixture, the intended behavior is one logical commit. That requires the editor's input and history layers to cooperate rather than independently recording every provisional DOM mutation.

Remote edits add a different concern. If a collaborator inserts text before the local selection, map the local endpoints through that operation. If an active composing region is affected, choose an explicit policy supported by the editor framework instead of replacing the entire document with a network snapshot.

A versioned transaction protocol, operational transformation, or a conflict-free replicated data type can help synchronize documents, but naming one does not solve selection or IME by itself. Explain document convergence, local pending edits, and view reconciliation separately. For an interview prototype, clearly state when collaboration is outside scope.

Which tests should you demonstrate?

The model test suite should cover insertion before a caret, insertion at a boundary with both association biases, deletion overlapping a selection, block merge, unsupported pasted content, and a transaction that changes both document and selection. Verify the resulting state, not just a string containing the expected word.

Browser tests should include forward and backward selections, toolbar focus transitions, multiline paste, undo after paste, emoji boundaries, and real composition in the supported environment. Add a remote-update test only if collaboration is in scope. Keep native-input observations separate from pure mapping assertions.

An especially useful demonstration starts with abcd and the caret before d, inserts XY before b, and shows the caret still before d. Then repeat with a backward selection spanning two blocks. The first proves a simple map; the second exposes whether your coordinate model is rich enough.

For failures, log event type, input intention, composition state, document version, and mapped selection, while avoiding raw private document content. That produces an inspectable sequence without turning debugging telemetry into a privacy leak.

Practice editing as a state transition

Practice questionTopic-specific follow-up
Design a text editor with undo/redoGroup document and selection changes.
Design document layer with undo/redoCompare immutable documents and inverse operations.
Design a reusable React comment componentSeparate editor-local state from saved comments.
Build a Reliable Streaming Chat UIReconcile remote updates without overwriting active input.
Implement debounced async autocomplete inputPreserve composition and stale-response boundaries.

For one exercise, describe the transaction before writing its handler. Specify the document change, selection change, history boundary, and whether native composition currently owns the affected region.

Finish with a coherent editor contract

Rich text editor interview questions are not answered by adding bold buttons around contenteditable. Show a supported document schema, model-based selection, composition-aware input ownership, and transaction-based history. Then demonstrate one boundary failure and explain how your chosen editor architecture prevents it.

Use the document-layer undo/redo task to rehearse a selection-mapping trace and composition ownership policy. Keep the production guarantees no broader than the environments you actually tested.

Sources and Further Reading

Research checked October 1, 2026. The offset map and document scenarios are original exercises. Pure tests do not reproduce native IME, cross-browser editing, or real-time collaboration behavior.