Scenarios
A scenario groups multiple cases that describe the same phenomenon across different operating systems, devices, browsers, or keyboard setups.
IME & Composition
Baseline typing and composition in a simple contenteditable region
This case describes a baseline scenario for inspecting how a plain `contenteditable` region behaves
beforeinput and input events have different inputType values
During IME composition or in certain browser/IME combinations, the beforeinput event may have a different inputType than the corresponding input event. For example, beforeinput may fire with insertCompositionText while input fires with deleteContentBackward. This mismatch can cause handlers to misinterpret the actual DOM change and requires storing beforeinput's targetRanges for use in input event handling.
Selection mismatch between beforeinput and input events
The selection (window.getSelection()) in beforeinput events can differ from the selection in corresponding input events. This mismatch can occur during IME composition, text prediction, or when typing adjacent to formatted elements like links. The selection in beforeinput may include adjacent formatted text, while input selection reflects the final cursor position.
beforeinput not cancelable during IME composition
Some beforeinput events during IME composition cannot be canceled per spec or implementation—calling preventDefault may throw or be ignored, so editors cannot always block native insertion.
Browser translation breaks contenteditable editing
When browser translation features (like Google Translate) are activated, they manipulate the DOM by replacing text content and injecting elements. This can break contenteditable functionality, causing cursor positioning issues, event handling problems, and IME composition failures.
Composition event lifecycle inconsistencies across browsers
Analysis of how out-of-order or missing composition events disrupt editor state synchronization.
getTargetRanges() returns empty array in beforeinput events
The getTargetRanges() method in beforeinput events may return an empty array or undefined in various scenarios, including text prediction, certain IME compositions, or specific browser/device combinations. When getTargetRanges() is unavailable, developers must rely on window.getSelection() as a fallback, but this may be less accurate.
Backspace granularity during Chinese IME on Android
On Android with Chinese IME, Backspace may delete whole syllables, partial Pinyin, or confuse composition boundaries compared to desktop—frameworks that handle Backspace uniformly across platforms mis-handle mobile.
IME candidate list timing and conversion (kanji, hanzi)
Japanese kanji conversion and Chinese character selection depend on the IME candidate window. Delays, wrong ordering, or Safari-specific lag can cause users to commit the wrong character or see candidates that do not match the underlying buffer—especially under load or in complex layouts.
Combining characters and complex scripts during IME composition
Scripts that use combining marks, conjuncts, or tone marks (e.g. Thai, Devanagari, Vietnamese, Cyrillic) may compose differently across browsers. Diacritics can be lost, reordered, or split across DOM nodes when the editor normalizes or wraps text during composition.
Duplicate beforeinput or input events during IME composition
Some browsers and keyboards emit duplicate composition-related input or beforeinput events—especially iOS Safari dictation paths and certain Android keyboards—so naive handlers that insert text on every input may double characters or corrupt state.
Escape key during IME composition
Escape typically cancels IME composition or closes the candidate window. In Edge, Firefox, and other engines, timing and whether partial text remains in the DOM differ—Arabic and Korean IME cases show cross-browser variance.
Missing composition events on iOS (IME)
On some iOS Safari versions and keyboards, compositionstart or compositionupdate may not fire reliably for certain languages, while input events still fire—editors that only reconcile on composition boundaries can desync.
Blur and focus during IME composition (CJK and Japanese Safari)
Moving focus away from the editor while composing text (Chinese, Japanese, Korean) can cancel composition, commit partial text, or leave the IME candidate window out of sync. Safari often shows distinct behavior for Japanese; Chrome behavior for Chinese/Korean is covered in related cases.
IME composition when focus moves between elements (Korean and others)
If the user switches focus to another field, button, or nested contenteditable while Korean (or other) IME composition is active, browsers differ on whether composition is committed, cancelled, or leaves orphan state. Chrome, Safari, and Firefox do not agree; mobile adds more variance.
keyCode 229 and Enter during IME composition
During IME composition, keydown often reports keyCode 229 (VK_PROCESSKEY on Windows) for many keys, meaning the event is part of an input method sequence. Enter may commit composition, insert a newline, or be swallowed—Chrome vs Firefox vs Japanese layouts differ. Handlers that assume Enter always means insertParagraph break composition incorrectly.
Number keys for IME candidate selection (Japanese and Chinese)
Many IMEs let users pick candidates with number keys 1–9. In contenteditable, those keys may be consumed by the IME, intercepted by the page for shortcuts, or mis-handled by Safari—causing wrong selection or cancelled composition.
Paste during IME composition cancels or corrupts composition
Pasting from the clipboard while IME composition is active may cancel the composition session, replace the wrong range, or interleave pasted text with unfinished syllables—Firefox and Chrome show different behavior for Korean and Hindi IME paths.
Scrolling cancels or disrupts IME composition
User scrolling the page or scrollable editor while the IME candidate window is open may cancel composition or move the caret out of sync—reported on iOS Safari with Japanese IME and Android Chrome with Chinese IME when scroll containers move the editing context.
Tab key during IME composition (focus vs indent vs IME)
Tab moves focus by default. During IME composition, Tab may cancel composition, cycle candidates, or be captured by the editor for indentation—behavior differs for Chinese, Thai, and Safari vs Firefox.
IME composition causes duplicate text in headings (WebKit only)
When using IME to input CJK text in heading elements (H1, H2, etc.) in WebKit browsers, pressing Space to confirm composition causes both the raw Pinyin buffer AND the confirmed characters to appear together.
insertFromComposition and getTargetRanges() for IME commits
When composition ends, beforeinput may use inputType insertFromComposition or insertCompositionText. getTargetRanges() should describe the range to replace; on Safari (especially iOS) or with certain IMEs, ranges may be missing, wrong, or inconsistent with desktop Safari—breaking editors that rely on target ranges for transactions.
Korean IME composition causes editor crash (Firefox)
On Firefox with Windows 10 and Korean IME, specific key combination during IME composition causes the editor to crash. The crash occurs when typing certain sequences with the Korean IME.
Pinyin buffer visibility in Safari (Chinese IME)
When typing Chinese Pinyin in Safari, the Latin buffer (underlined or styled) may render differently than in Chrome—overlap with table cells, clipping, or missing underline—so users cannot see what they are composing before picking hanzi.
RTL scripts and character joining during IME composition (Arabic, Hebrew)
Arabic and Hebrew use right-to-left direction and contextual letter forms. During composition, joining rules, bidi isolation, and Safari vs Firefox may disagree—caret position and composed text can diverge from visual order.
IME composition start delay on Android
On Android Chrome and other WebView-based surfaces, compositionstart and the first compositionupdate can arrive later than on desktop after the user begins typing—especially for Japanese, Chinese, or Korean IMEs. Code that assumes immediate isComposing === true can mis-handle the first few keystrokes.
Chinese Pinyin candidate window in table cells (Safari and cross-browser)
When editing Chinese Pinyin inside a table cell—especially on iOS Safari—the IME candidate window can be clipped, positioned incorrectly, or behave differently than in a plain paragraph. Other browsers (Firefox, Edge, Chrome) also show layout-specific quirks.
IME candidate window positioning
The IME candidate list is anchored to the caret rect; viewport scroll, zoom, CSS transforms, and fixed containers can offset it from the user's expectation.
insertParagraph preventDefault breaks IME composition state in Safari
In Safari desktop, when preventDefault() is called on keydown or beforeinput events for insertParagraph (Enter key), the IME composition state becomes corrupted. Subsequent text input fails to trigger proper input events, causing characters to not be inserted or composition to malfunction.
iOS dictation triggers duplicate input events after completion
On iOS, when using voice dictation to input text into contenteditable elements, the system may fire duplicate beforeinput and input events after the initial dictation completes. The text is split into words and events are re-fired, causing synchronization issues. Composition events do not fire during dictation, making it difficult to distinguish dictation from keyboard input.
iOS Safari contenteditable — do not force re-render or change selection during input
On iOS Safari, input and beforeinput can fire with inputType 'insertText' multiple times (e.g. voice dictation) or with inputType undefined/null. Forcing re-render or changing selection during this flow desyncs the editor model from the DOM and can permanently break subsequent input.
Japanese IME candidate and conversion on Firefox
Firefox shows different candidate window behavior or conversion latency than Chrome for some Japanese IME backends—handlers tuned on Chromium may mis-handle conversion commits.
Korean IME composition order and events on Firefox
Firefox may dispatch composition and input events in a different order than Chromium for Korean IME—handlers that assume Chrome ordering desync.
Korean IME on Linux with Fcitx
Fcitx5/Fcitx hangul modules interact with Chromium and Firefox through different input paths than IBus—composition event ordering and Wayland vs X11 add variance.
Korean Hangul IME on Linux (Firefox vs Chromium)
IBus Hangul and other backends on Linux produce different composition sequences between Firefox and Chromium—especially around Wayland, XIM, and GTK_IM_MODULE.
Mac accent menu composition events are inconsistent
On macOS, using the accent menu (e.g., holding vowel key to select accented character, or using option+key combinations) does NOT consistently trigger standard IME composition events (`compositionstart`, `compositionupdate`, `compositionend`). This makes it difficult to distinguish accent menu input from IME input or regular keyboard input.
Samsung keyboard at link boundaries (node split)
Samsung Keyboard with text prediction can split or duplicate inline link nodes at boundaries—similar to other prediction issues but specific to link-adjacent typing.
Space key behavior during IME composition
During active IME composition, pressing Space may commit the segment, insert a literal space, be ignored, or cancel composition—depending on language, IME, and browser. Editors that assume Space always inserts U+0020 can lose characters or break composition state.
IME composition text leaks outside table cells
A technical evaluation of why IME composition often fails when anchored inside empty table structures.
Undo and redo during IME composition
Pressing Undo or Redo while IME composition is active can cancel composition, leave partial syllables, or corrupt the undo stack. Behavior differs by browser and by whether the editor uses native undo or a custom history layer.
Formatting
Background color changes behave inconsistently
Changing background color (highlighting) in contenteditable elements behaves inconsistently across browsers. Background colors may be applied as inline styles, may not persist when typing, or may interfere with text selection. The behavior differs from text color changes.
Blockquote editing behavior varies across browsers
Editing text within blockquote elements in contenteditable behaves inconsistently across browsers. Pressing Enter, applying formatting, or pasting content may break the blockquote structure, create nested blockquotes, or behave unexpectedly.
Code block editing behavior varies across browsers
Editing text within code blocks (<pre><code>) in contenteditable elements behaves inconsistently across browsers. Line breaks, indentation, whitespace preservation, and formatting may be handled differently, making it difficult to maintain code formatting.
Empty elements accumulate in DOM during editing
During editing operations, empty elements (empty paragraphs, divs, spans with no content) accumulate in the DOM. These elements can cause layout issues, make the HTML bloated, and create unexpected behavior. Browsers handle empty element cleanup inconsistently.
Enter vs Shift+Enter behavior differs across browsers
The behavior of Enter and Shift+Enter keys in contenteditable elements varies across browsers. Enter may create a new paragraph, line break, or div, while Shift+Enter may create a line break or behave differently. The resulting DOM structure also varies.
execCommand is deprecated but still widely used for formatting
The document.execCommand() API, which is commonly used to apply formatting (bold, italic, etc.) in contenteditable regions, has been deprecated. However, there is no complete replacement, and many implementations still rely on it. This creates uncertainty about future browser support.
Font family changes behave inconsistently
Changing font family in contenteditable elements behaves inconsistently across browsers. The font-family CSS property may be applied inline, as a style attribute, or may not be applied at all. The behavior also varies when editing text after applying a font.
Font size changes behave inconsistently
Changing font size in contenteditable elements behaves inconsistently across browsers. Font sizes may be applied as inline styles, as font tags, or may not persist when typing new text. The unit (px, em, rem) handling also varies.
Bold formatting is lost when typing after applying bold
When applying bold formatting to selected text and then continuing to type, the bold formatting is not maintained for the newly typed characters in Safari.
HTML entity encoding and decoding is inconsistent
Special characters in contenteditable elements may be encoded as HTML entities (<, >, &, etc.) or decoded to their actual characters inconsistently across browsers. This can cause issues when copying, pasting, or serializing content.
BR Tag Loss When Typing After Selected Line in Internet Explorer 11
In Internet Explorer 11, typing after selecting a line of text in a contenteditable div can unexpectedly delete the BR tag, causing lines to merge.
Image deletion behavior varies across browsers
Deleting images from contenteditable elements behaves differently across browsers. Some browsers delete the image cleanly, while others may leave empty elements, break the DOM structure, or require multiple delete operations.
Image insertion behavior varies across browsers
When inserting images into contenteditable elements, the behavior varies significantly across browsers. Images may be inserted as <img> tags, as base64 data URLs, or may not be supported at all. The size, positioning, and editing behavior also differs.
Image resizing in contenteditable is limited or inconsistent
Resizing images within contenteditable elements is limited or behaves inconsistently across browsers. Some browsers support native resize handles, while others require manual implementation. The resize behavior may also affect the DOM structure unexpectedly.
Deleted inline elements recreated when typing in contenteditable
After deleting an empty or inline element (e.g. span, b) inside contenteditable, typing causes the browser to recreate the deleted element, leading to unpredictable DOM and editor state.
insertHTML breaks DOM structure and formatting
When using document.execCommand('insertHTML', ...) to insert HTML content into a contenteditable region, the DOM structure may be broken or reformatted unexpectedly. Nested elements may be flattened or reorganized.
Line break element type varies across browsers
When creating line breaks in contenteditable elements, browsers use different HTML elements: <br>, <p>, or <div>. This inconsistency makes it difficult to predict and normalize the DOM structure, especially when working with rich text editors.
Link clicks interfere with contenteditable editing
When a link is inside a contenteditable element, clicking on the link may navigate away or trigger unexpected behavior instead of allowing text editing. The behavior varies across browsers and can make it difficult to edit link text or select links for deletion.
Link insertion and editing behavior varies across browsers
When inserting or editing links in contenteditable elements, the behavior varies significantly across browsers. Creating links, editing link text, and removing links can result in unexpected DOM structures or lost formatting.
Link as non-anchor markup during editing (e.g. span + data-href)
Some editors keep URLs on a span (or other non-anchor inline) with data-* attributes while the user edits, then serialize to semantic <a href> for publish or clipboard. Mainstream framework defaults still use <a> in the live DOM; span-based linking is a deliberate product/engineering choice with distinct trade-offs.
List formatting is lost when editing list items
When editing text within list items, formatting such as bold, italic, or links may be lost or behave unexpectedly. The list structure itself may also be lost when certain operations are performed, such as pasting content or applying formatting.
List item deletion behavior varies across browsers
When pressing Backspace or Delete at the beginning or end of a list item, the behavior varies significantly across browsers. Some browsers delete the list item and merge with adjacent content, while others may delete the entire list or create unexpected DOM structures.
Nested formatting elements create complex DOM structures
Applying multiple formatting operations (bold, italic, underline, etc.) creates nested HTML elements that can become complex and hard to manage. Browsers handle nested formatting differently, and the resulting DOM structure can be inconsistent.
Nested inline spans from formatting toggles
Repeated bold/italic toggles or browser execCommand can nest spans deeply—serialization, selection, and IME boundaries degrade.
Nested list editing behavior is inconsistent
When editing nested lists (lists within list items), the behavior of Enter, Backspace, Delete, and Tab keys varies significantly across browsers. Creating, editing, and deleting nested list items can result in unexpected DOM structures or lost formatting.
Table editing in contenteditable is limited and inconsistent
Editing tables within contenteditable elements is limited and behaves inconsistently across browsers. Creating tables, editing cells, adding/removing rows and columns, and maintaining table structure all have browser-specific behaviors and limitations.
Text color changes behave inconsistently
Changing text color in contenteditable elements behaves inconsistently across browsers. Colors may be applied as inline styles, as font tags, or may not persist when typing. The color format (hex, rgb, named colors) handling also varies.
Typing adjacent to formatted elements causes unexpected behavior
When typing text next to formatted elements (links, bold, italic, etc.) in contenteditable, the input events may include the formatted element's text in event.data, selection ranges may include the formatted element, and text may be inserted into the formatted element instead of after it. This occurs across different browsers and input methods.
Undo/redo stack management is inconsistent
The undo/redo stack in contenteditable elements behaves inconsistently across browsers. Programmatic DOM changes may or may not be added to the undo stack, and the stack may be cleared unexpectedly. Custom undo/redo implementation is often necessary.
Paste & Copy
Caret position jumps unexpectedly after pasting content
After pasting content into a contenteditable region, the caret position does not end up at the expected location, sometimes jumping to the beginning of the pasted content or to an unexpected position.
Clipboard API paste does not work in contenteditable
When using the Clipboard API (navigator.clipboard.readText() or navigator.clipboard.read()) to programmatically paste content into a contenteditable region, the paste operation may fail or not work as expected.
preventDefault on paste event does not prevent default paste behavior
In Chrome on Windows, calling `preventDefault()` on the `paste` event does not always prevent the default paste behavior. Content may still be pasted despite the prevention.
Pasting rich text into contenteditable strips markup unexpectedly
When pasting content from a rich text source into a contenteditable element, the resulting DOM loses headings, lists, or inline formatting that were present in the source.
Link pasting behavior differs across browsers
When pasting links into contenteditable elements, different browsers handle the link data differently. Some browsers paste only the URL, while others preserve the link title and HTML structure.
Pasting images into contenteditable is not supported consistently
When attempting to paste images (from clipboard) into a contenteditable region, the behavior is inconsistent across browsers. Some browsers ignore the paste, while others may insert a placeholder or fail silently.
Selection
contenteditable=false dismisses selection on Android Chrome
Tapping or moving across contenteditable=false regions on Android can collapse selection or clear the caret in ways that differ from desktop Chrome.
Browser zoom causes caret and selection positioning issues
When the browser is zoomed (or content is scaled via CSS transforms), caret position and text selection in contenteditable elements can become inaccurate. Clicking at a certain position places the caret elsewhere, and selection highlights may not match the visual selection.
Text caret is invisible on position:relative elements
When editing content inside an element with `position:relative`, the text caret (cursor) is completely invisible. Text can be typed and appears in the editor, but there's no visual feedback of where the insertion point is located.
Typing certain characters makes cursor jump on Chrome Mobile
On Chrome Mobile for Android, typing certain punctuation characters (commas, colons, semicolons, quotes, etc.) in the middle of a word causes the cursor to jump to the end of the word instead of staying at the insertion point.
Caret jumps to end when deleting character next to non-editable element
When deleting the last character before a non-editable "pill" or tag element (contenteditable="false") in a contenteditable div in Chrome, the caret (cursor) jumps to the end of the entire contenteditable div instead of staying adjacent to the remaining content.
Contenteditable isolation and selection in Shadow DOM
Analysis of the architectural friction between the single-selection document model and Web Component encapsulation.
Selection is lost after copying content in contenteditable
After copying selected text in a contenteditable region using Cmd+C, the selection is lost in Safari. The user must re-select the text to perform additional operations.
CSS contain property may affect contenteditable selection
When a contenteditable element or its parent has the CSS contain property, selection behavior may be affected. Selection may not extend beyond the contained element, and caret movement may be restricted.
CSS transform may cause selection handles to appear in wrong position
When a contenteditable element has CSS transforms applied (translate, scale, rotate), the selection handles and caret may appear in incorrect positions. The visual position may not match the actual selection position.
Touch drag to extend selection on mobile Safari and others
Drag handles and touch selection on iOS Safari can conflict with scroll gestures, nested editables, and custom overlays—selection may collapse or jump compared to desktop.
RTL text direction and selection behavior inconsistent in contenteditable
Right-to-left (RTL) and mixed-direction text in contenteditable causes caret misalignment, scroll failures, and select-all behavior that differs from LTR and from spec.
Select All (Ctrl+A) collapses wrong way when non-editable block is first or last child
When a contenteditable element has a non-editable block as its first or last child, Ctrl+A (Select All) collapses the selection in the wrong direction instead of selecting all content, breaking WYSIWYG expectations.
selection.addRange not working correctly in Safari
When setting cursor position using `selection.addRange()` in a contenteditable element, it works correctly in Chrome and Firefox but fails in Safari. The selection "pops out" of intended marker element and moves to the next sibling's text node instead of staying within the marker.
window.getSelection() returns null when contenteditable loses focus
When a contenteditable region loses focus, window.getSelection() may return null in Safari, even if there was a valid selection before the focus loss. This makes it difficult to preserve or work with selections.
Selection collapses unexpectedly when clicking outside contenteditable
When a range of text is selected inside a `contenteditable` element, clicking outside the element
Selection range is incorrect when selecting across multiple elements
When selecting text that spans across multiple HTML elements (e.g., p, div, span) in a contenteditable region, the selection range may not accurately reflect the visual selection. The Selection and Range APIs may return incorrect boundaries.
Selection restoration after DOM manipulation is unreliable
After programmatically manipulating the DOM in a contenteditable element, restoring the text selection (cursor position) is unreliable across browsers. The selection may be lost, moved to an incorrect position, or become invalid.
Caret & Navigation
Dark mode causes caret visibility and styling issues
When browser dark mode is enabled, contenteditable elements may experience invisible or poorly visible caret, inline style injection conflicts, background color issues, and form control styling problems. These issues are caused by missing color-scheme declarations and conflicts between browser-injected styles and custom CSS.
Arrow keys move by word instead of character when modifier is not pressed
In Chrome on Windows, arrow keys may move the caret by word instead of by character, even when no modifier keys are pressed. This makes precise cursor positioning difficult.
Arrow keys skip over emoji in contenteditable
When using the left and right arrow keys in a `contenteditable` element that contains emoji, the
Framework state synchronization issues with contenteditable
When using contenteditable with JavaScript frameworks like Vue, Angular, or Svelte, state synchronization between the DOM and framework state can cause caret position issues, event mismatches, and performance problems. Each framework has unique challenges when integrating with contenteditable.
Caret position jumps to beginning on React re-render
When using contentEditable elements in React, the caret (cursor) position jumps to the beginning of the element whenever the component re-renders. This occurs because React's reconciliation process replaces DOM nodes, causing the browser to lose track of the caret position. This issue is more prevalent in Safari and Firefox.
Mobile & Touch
Input Events Fire on Focus/Blur in Chrome Android
In Chrome on Android, input events may fire when a contenteditable element gains or loses focus, even without content changes. This behavior can lead to unintended side effects in applications relying on input events for content modification detection.
CSS backdrop-filter may cause rendering issues in contenteditable
When a contenteditable element has CSS backdrop-filter applied, rendering may be affected. Text may appear blurry, selection may not render correctly, and performance may be degraded, especially on mobile devices.
enterkeyhint attribute does not work on contenteditable
The enterkeyhint attribute, which controls the label on the Enter key on mobile keyboards, does not work on contenteditable elements. The Enter key label remains the default regardless of the attribute value.
enterkeyhint and inputmode affect Enter key behavior inconsistently
On mobile devices, the combination of enterkeyhint and inputmode attributes may affect Enter key behavior inconsistently on contenteditable elements. The Enter key may insert line breaks when it should perform an action, or vice versa.
inputmode attribute does not affect virtual keyboard on mobile
The `inputmode` attribute, which should control the type of virtual keyboard shown on mobile devices, does not work on contenteditable regions in iOS Safari. The keyboard type cannot be controlled.
iPhone keyboard hides text when entering on contenteditable
On iPhone/iPad Safari, when entering text or pressing "return" multiple times in a contenteditable element, the software keyboard appears but hides the text being typed. The page doesn't auto-scroll to keep text visible. Works fine on Android and other browsers.
Broken viewport mechanics when software keyboard is visible (iOS Safari)
On iOS Safari, when the software keyboard becomes visible, viewport calculations become unreliable. `position:fixed` elements break, `height` returns incorrect values, and absolute positioning with `top`/`bottom` fails. This severely affects editors with floating toolbars or positioned elements.
Media query layout changes may disrupt contenteditable editing
When a page with a contenteditable element responds to media query changes (e.g., orientation change, window resize), the layout changes may disrupt editing. The caret position may jump, and selection may be lost.
Touch events interfere with contenteditable focus on mobile
On iOS Safari, touch events (tap, long-press) on a contenteditable region may not properly focus the element. The virtual keyboard may not appear, or focus may be lost unexpectedly.
Backspace with Samsung Keyboard causes editor crash
On Android with Samsung Keyboard, holding the backspace key to delete text causes the contenteditable editor to crash completely. JavaScript execution stops and page becomes unresponsive.
Samsung Keyboard Text Prediction Issues in contenteditable
Samsung keyboard's text prediction feature causes various input event handling issues in contenteditable elements on Android Chrome, including insertCompositionText events, missing getTargetRanges(), selection mismatches, and combined event.data when typing adjacent to links or formatted elements.
Touch selection handles are difficult to use on mobile devices
On mobile devices, selecting text in a contenteditable region using touch is difficult. The selection handles are small and hard to grab, and the selection range may change unexpectedly when trying to adjust it.
Accessibility
Accessibility Foundations: Screen Readers, ARIA, and the AX-Tree
Ensuring contenteditable editors are navigable for assistive technology users through proper ARIA mapping and engine synchronization.
role="textbox" and screen reader behavior with contenteditable
Assistive technologies map contenteditable to textbox-like semantics when authors use role=textbox or aria-multiline—conflicts with actual HTML semantics and browser AX trees can confuse announcements.
Browser extensions interfering with contenteditable (Grammarly and others)
Extensions inject overlays, mutate DOM, or listen to input for grammar and translation—breaking framework-controlled editors, selection restoration, and IME composition boundaries.
Native spellcheck interfering with editing
Browser spellcheck underlines and may mutate DOM or fire input-adjacent updates—conflicting with custom dictionaries, code blocks, and IME composition.
Voice and speech-driven input in contenteditable lacks a stable editing contract
OS voice typing, Web Speech API, and assistive voice tools insert or mutate contenteditable without the same event sequence as keyboard or IME. Caret position, selection, and composition events are inconsistent across platforms, which breaks editors that assume beforeinput/input/composition alignment.
Performance
Auto-scroll while typing in contenteditable
Browsers try to keep the caret visible by scrolling the editable container or the page. During rapid typing—especially near the bottom or right edge—scroll updates can lag, batch, or feel jarring, so the caret temporarily leaves the viewport or the view jumps unexpectedly.
Chrome spellcheck performance regression (v96 era)
A known Chromium regression around spellcheck and large contenteditable regions caused severe typing lag—documented for planning workarounds such as spellcheck=false or chunking.
CSS filter may affect contenteditable performance
When a contenteditable element has CSS filters applied (blur, brightness, etc.), editing performance may be degraded. Typing may lag, and selection may be slow to update.
CSS will-change may improve or degrade contenteditable performance
When a contenteditable element has CSS will-change property set, performance may be affected. In some cases, it may improve performance by hinting the browser about upcoming changes. In other cases, it may degrade performance by creating unnecessary layers.
Memory growth in long-running contenteditable sessions
Large documents, retained DOM references, MutationObserver chains, and undo stacks can leak memory if not detached—especially in single-page apps that keep the editor mounted for hours.
MutationObserver may interfere with contenteditable editing
When a MutationObserver is attached to a contenteditable element or its parent, the observer callbacks may interfere with editing performance. Frequent DOM mutations during typing can trigger many observer callbacks, causing lag or jank.
Performance Foundations: Complexity, Memory, and Thrashing
Managing exponential slowdowns in large documents and browser-specific engine thrashing.
Typing and layout performance in very large contenteditable documents
Huge DOM trees make each keystroke expensive: layout, style recalc, and spellcheck can block input—virtualization or chunking is often required.
Selection performance in large contenteditable documents
getSelection(), getRangeAt, and DOM walks over very large contenteditable trees can block the main thread when the user selects all or drags across thousands of nodes—mobile devices suffer first.
ResizeObserver may cause layout shifts during contenteditable editing
When a ResizeObserver is attached to a contenteditable element, the observer may trigger during editing as content changes size. This can cause layout recalculations and visual jumps, especially when the contenteditable has dynamic height.
Virtual scrolling libraries interfere with contenteditable selection
When a contenteditable element is used with virtual scrolling libraries (e.g., for large documents), the virtual scrolling mechanism may interfere with text selection and caret positioning. The selection may be lost when elements are removed from the DOM during scrolling.
Focus & Blur
autofocus attribute does not work on contenteditable
The autofocus attribute, which automatically focuses form inputs on page load, does not work on contenteditable elements. There is no built-in way to automatically focus a contenteditable region when a page loads.
Focus is lost when clicking on certain elements within contenteditable
When a contenteditable region contains interactive elements (buttons, links, etc.), clicking on these elements causes the contenteditable to lose focus. This interrupts the editing flow and may cause the caret to disappear.
Programmatic focus selects all content
In Chrome and Safari, calling focus() on a contenteditable div can select the entire content instead of placing the cursor at the beginning, as observed in Firefox and IE.
Fullscreen API may affect contenteditable focus and selection
When a contenteditable element enters or exits fullscreen mode using the Fullscreen API, focus and selection may be lost. The caret position may reset, and editing may be disrupted.
Nested contenteditable elements cause focus and selection issues
When a contenteditable element contains another contenteditable element, focus behavior becomes unpredictable. Clicking on the nested element may not properly focus it, and selection ranges may span across both elements incorrectly.
Page Visibility API may affect contenteditable during tab switches
When a page with a contenteditable element becomes hidden (tab switch, minimize), the Page Visibility API may affect editing state. Focus may be lost, and composition may be interrupted.
tabindex attribute does not control focus order correctly
When multiple contenteditable regions have `tabindex` attributes, the tab order may not follow the `tabindex` values correctly in Edge. The focus order may be inconsistent or incorrect.
WebKit contenteditable Focus Bug
A known bug in WebKit browsers prevents focus from transferring correctly from contenteditable elements to non-editable elements. A workaround involves using a hidden input field to manage focus transitions.
Other
beforeinput event is not supported in Safari
The beforeinput event, which is crucial for intercepting and modifying input before it's committed to the DOM, is not supported in Safari. This makes it difficult to implement custom input handling that works across all browsers.
contenteditable behavior differs when inside an iframe
When a contenteditable region is inside an iframe, its behavior may differ from when it's in the main document. Selection, focus, and event handling may be inconsistent.
contenteditable inheritance behavior is inconsistent
When a parent element has contenteditable="true" and a child element has contenteditable="false", the inheritance behavior is inconsistent across browsers. Some browsers allow editing in the child, while others correctly prevent it. The behavior may also differ when the child has contenteditable="inherit" or no contenteditable attribute.
contenteditable="false" on child elements is not respected consistently
When a contenteditable region contains child elements with contenteditable="false", the behavior is inconsistent. Some browsers allow editing within these elements, while others correctly prevent it.
contenteditable in table cells causes layout issues
When a contenteditable region is inside a table cell (`<td>`), editing the content may cause layout issues in Firefox. The table may resize unexpectedly or the cell may overflow.
CORS restrictions may affect contenteditable in cross-origin iframes
When a contenteditable element is inside a cross-origin iframe, CORS restrictions may prevent certain operations. Accessing the contenteditable from the parent frame may be blocked, and some editing operations may be restricted.
Content Security Policy may restrict contenteditable behavior
When a page has a strict Content Security Policy (CSP), certain contenteditable operations may be restricted. Pasting content, executing scripts, or inserting HTML may be blocked depending on the CSP directives.
CSS isolation property may affect contenteditable stacking context
When a contenteditable element has the CSS isolation: isolate property, it creates a new stacking context. This may affect how selection handles and IME candidate windows are positioned relative to the element.
CSS mix-blend-mode may affect contenteditable text rendering
When a contenteditable element has CSS mix-blend-mode applied, text rendering may be affected. Text may appear with incorrect colors, selection may not be visible, and caret may not render correctly.
Delete key behavior is inconsistent with Backspace
In Firefox on Linux, the Delete key behaves differently from Backspace in ways that are inconsistent. Delete may remove different amounts of text or behave unexpectedly compared to Backspace.
disabled attribute does not disable contenteditable
The `disabled` attribute, which disables form inputs, does not work on contenteditable regions in Safari. The contenteditable remains editable and interactive even when `disabled` is set.
Pressing Enter inserts two line breaks in contenteditable
In a plain `contenteditable` element, pressing Enter inserts two visible line breaks instead of one.
File API drag and drop does not work in contenteditable
When trying to drag and drop files into a contenteditable element, the File API may not work as expected. File drop events may not fire, or file content may not be accessible.
contenteditable content is not included in form submission
When a contenteditable region is inside a form, its content is not automatically included in form submission. Unlike input and textarea, contenteditable content must be manually extracted and added to the form data.
lang attribute does not affect spellcheck language
The `lang` attribute on a contenteditable region does not affect the spellcheck language in Safari. Spellcheck always uses the browser's default language, regardless of the `lang` attribute value.
maxlength attribute is not supported on contenteditable
The `maxlength` attribute, which works on `<input>` and `<textarea>` elements, is not supported on contenteditable regions. There is no built-in way to limit the amount of content that can be entered.
pattern attribute does not validate contenteditable content
The `pattern` attribute, which allows regex-based validation on form inputs, does not work on contenteditable regions. Content cannot be validated against a pattern.
readonly attribute does not prevent editing in contenteditable
The `readonly` attribute, which should prevent editing on form inputs, does not work on contenteditable regions in Firefox. Users can still edit the content even when `readonly` is set.
required attribute is not supported for validation
The required attribute, which works on form inputs to indicate mandatory fields, is not supported on contenteditable regions. There is no built-in way to mark a contenteditable as required for form validation.
Undo and redo behavior is inconsistent across browsers
The undo and redo functionality (Ctrl+Z / Ctrl+Y or Cmd+Z / Cmd+Shift+Z) behaves differently across browsers. Some browsers undo individual keystrokes, while others undo larger operations. The undo stack may also be cleared unexpectedly.
contenteditable behavior differs inside Web Components
When a contenteditable element is inside a Web Component (custom element), its behavior may differ from when it's in standard HTML. Event handling, selection, and focus management may be affected by the component's shadow DOM or encapsulation.
XSS protection may interfere with contenteditable HTML insertion
Browser XSS protection mechanisms may interfere with programmatic HTML insertion in contenteditable elements. Script tags or event handlers inserted via innerHTML or similar methods may be stripped or sanitized.
clipboard
Code block indentation lost on paste or format
Leading spaces and tabs in pasted code can collapse to a single space or be stripped when the editor normalizes to paragraphs or applies pre-wrap inconsistently.
Clipboard and paste behavior in Edge on Linux
Edge on Linux (Chromium-based) can differ from Windows Edge for clipboard MIME types, file paste, and integration with Wayland clipboard—paste into contenteditable may drop images or format differently.
Pasting images as base64 in IE11 and SharePoint contexts
Legacy IE11 and enterprise paste pipelines could embed images as large base64 data URIs in contenteditable HTML—performance and security implications for sanitizers.
Paste preserves formatting inconsistently across sources
The same paste pipeline may keep bold from Google Docs but strip it from Notion, or preserve inline styles in Chrome but normalize differently in Safari—clipboard HTML and browser sanitizers vary.
Plain text paste and plaintext-only contenteditable
Rich paste into contenteditable pulls in unwanted HTML; users expect paste-as-plain-text or plaintext-only modes. Browsers differ on clipboard APIs, execCommand, and how NBSP and whitespace survive—breaking layout when editors assume 'plain' means U+0020 only.
Trailing and leading whitespace on paste
Firefox and other browsers may preserve or normalize trailing newlines and spaces differently when pasting plain text—collaborative editors and diffs see unexpected whitespace changes.
input
innerHTML and serialization differ across browsers
The same DOM edited in contenteditable may serialize to different markup strings in Safari vs Chrome—attribute order, implied tags, and span wrappers for styles.
Caret jumps to end after DOM manipulation in Chrome
In Chromium, programmatic DOM updates (normalization, wrapping, React reconciliation) while the user is typing can move the caret to the end of the contenteditable or to an unexpected boundary—especially when the mutation happens between keystrokes.
HTML Drag and Drop API with contenteditable
Using the HTML drag-and-drop API inside or alongside contenteditable regions often diverges from behavior on plain elements: default actions, `contenteditable` hit-testing, and `beforeinput`/`drop` ordering differ by browser. Custom editors must reconcile native DnD with their own selection model.
Drag-and-drop duplicates elements in Firefox
Dragging selected content inside a contenteditable region on Firefox can duplicate nodes or leave ghost fragments—different from Chrome's behavior.
Empty paragraphs and br handling in contenteditable
Browsers disagree on how empty blocks are represented (<p><br></p>, <p></p>, <div><br></div>) and how Backspace merges them. Editors that normalize on every keystroke can fight the user or create nested spans.
Cursor disappears near contenteditable=false boundaries in Firefox
Firefox may hide or misplace the caret when moving across contenteditable=true/false boundaries—widgets and embeds inside editors are affected.
Caret not visible in empty div on Firefox
Firefox may not show a caret in an empty block-level contenteditable container until the user types or a br placeholder exists—layout and min-height interact with focus rings.
Firefox undo stack corrupted when DOM mutates during editing
In Firefox, programmatic DOM changes during typing (auto-formatting, spellcheck fixes, framework reconciliation) can desynchronize the internal undo stack. Undo/redo may jump to wrong snapshots or truncate history.
getTargetRanges() can reference the wrong contenteditable when editors are nested
On some engines (notably Firefox for Android / Fenix), beforeinput getTargetRanges() may describe the outer contenteditable host instead of the inner focused editor. Custom handlers that trust targetRanges alone may delete or insert in the parent surface while the user believes they are typing in a nested field.
Non-editable regions and double-click to edit in IE11
Legacy IE11 had quirks when mixing contenteditable=false regions with adjacent editables—double-click could focus the wrong host or fail to enter edit mode.
Paragraph splitting and block behavior in editors
Enter key handling, splitBlock commands, and browser-default paragraph creation differ—ProseMirror and native contenteditable can disagree, causing crashes or empty blocks at boundaries.
Focus in table cells with contenteditable (legacy IE)
Internet Explorer and old EdgeHTML had specific bugs when focusing contenteditable inside table cells—caret not appearing, wrong active element, or selection stuck in adjacent cells.
Undo stack and programmatic DOM changes
Programmatic inserts or execCommand during typing can split undo transactions or clear the stack—browser-specific rules differ from custom editor history.
ui
Caret scrolls out of view during typing
Automatic scroll-to-caret may fail when the editable is inside nested scrollers, overflow hidden ancestors, or during rapid input—the user loses sight of the insertion point without manual scroll.
IME UI & Experience: Viewports, Candidates, and Layout
Managing browser UI collisions, virtual keyboard resizing, and IME candidate window positioning.
Caret visibility after scroll on iOS Safari
After the user or the page scrolls while editing in iOS Safari, the caret may render in the wrong place, disappear until the next tap, or sit outside the visible viewport—especially with fixed headers or virtual keyboard resize.
Software keyboard does not appear when focusing contenteditable
On some mobile browsers, focusing a contenteditable programmatically or from a non-gesture path may not raise the virtual keyboard—users cannot type until they tap again.
Page scroll when the mobile keyboard opens
Mobile browsers may scroll the page to bring the focused field into view when the virtual keyboard opens—sometimes overscrolling or hiding fixed UI and the caret.
Viewport resize when the virtual keyboard opens (Android Chrome)
The visual viewport shrinks when the keyboard appears; fixed toolbars, sticky UI, and caret visibility interact with resize and scroll events differently than desktop.
Placeholder interference with IME and DOM mutations
Technical analysis of how CSS and attribute-based placeholders disrupt text insertion and IME sessions.