A living catalog of
contenteditablebehavior across browsers, operating systems, and input methods.
The contenteditable attribute is deceptively simpleβadd it to any HTML element and users can edit its contents. But beneath this simplicity lies a minefield of browser-specific quirks, OS-dependent behaviors, and IME complications that have frustrated developers for decades.
When you use contenteditable in production, you quickly discover that:
- The same code behaves differently across Chrome, Firefox, Safari, and Edge
- IME (Input Method Editor) behavior varies dramatically between Windows, macOS, and Linux
- Event sequences (
beforeinput,input,compositionstart, etc.) fire in different orders depending on the browser - Selection and Range APIs have subtle but critical differences that break editor features
- Undo/redo stacks are cleared unexpectedly or don't include programmatic changes
- Paste behavior is inconsistent, sometimes preserving formatting, sometimes stripping it
- Mobile browsers introduce entirely new sets of quirks with touch interactions
These aren't edge casesβthey're the daily reality of building rich text editors. Major projects like ProseMirror, Slate, and Lexical have spent years working around these issues, but their solutions are often proprietary or too complex for smaller projects.
contenteditable.lab exists to document these behaviors systematically so that:
- π You can observe β Real-world edge cases captured with precise reproduction steps and environment details
- π You can search β Cases organized by environment (OS Γ Browser Γ Input Method) so you can find issues specific to your users
- π§ͺ You can reproduce β Interactive playground to verify behaviors in your own environment before shipping code
- π You can learn β Comprehensive documentation on events, Selection API, and proven workarounds
Each case documents a specific contenteditable behavior observed in a particular environment. A case includes:
Case: ce-0002-ime-enter-breaks
βββ Environment: Windows Γ Chrome Γ Korean IME
βββ Title: Composition is cancelled when pressing Enter
βββ Description: Detailed explanation of what happens and why
βββ Reproduction Steps: Step-by-step instructions to trigger it
βββ Expected Behavior: What should happen according to specs
βββ Observed Behavior: What actually happens in this environment
βββ Analysis: Technical explanation if known
βββ DOM Steps: Visual representation of DOM changes
βββ Status: confirmed (verified) / draft (needs verification)
Why cases matter: When a user reports "the editor breaks when I type Korean," you can search for cases with Korean IME tag and find the exact scenario, reproduction steps, and potential workarounds. Cases are searchable by:
- OS (Windows, macOS, Linux, iOS, Android)
- Browser (Chrome, Firefox, Safari, Edge)
- Device (Desktop, Mobile, Tablet)
- Keyboard layout (US QWERTY, Korean IME, Japanese IME, etc.)
- Tags (ime, composition, selection, paste, undo, etc.)
Scenarios group related cases that describe the same phenomenon across different environments. This helps you understand:
- Which environments are affected β Is this a Chrome-only issue or does it affect all browsers?
- Which environments need testing β Are there gaps in our coverage?
- The scope of the problem β Is this a universal issue or environment-specific?
Example scenario:
"IME composition cancelled on Enter"
This scenario groups cases where pressing Enter during IME composition cancels the composition unexpectedly:
- Windows + Chrome + Korean IME β (confirmed)
- macOS + Safari + Japanese IME β (confirmed)
- Linux + Firefox + Chinese IME ? (needs testing)
- iOS Safari + Chinese IME ? (needs testing)
Each scenario page includes:
- Description of the phenomenon
- Impact on user experience and development
- Browser comparison showing which browsers are most/least affected
- Workarounds and solutions that have been tested
- Related cases with links to specific environment combinations
- Graph visualization showing relationships between cases, scenarios, and tags
An interactive testing ground where you can:
- Type and observe β Type in a
contenteditableregion and watch events fire in real-time - Visualize ranges β See selection, composition, and
beforeinputranges overlaid on the editor - Track DOM changes β Visualize deleted and added text regions with color-coded highlights
- Detect invisible characters β See ZWNBSP, NBSP, LF, CR, TAB, and other invisible characters
- Identify non-editable areas β Highlight
contenteditable="false"regions within selections - Capture snapshots β Automatically save snapshots when anomalies are detected, with full event logs and environment info
- Browse event history β View detailed event logs with timing, DOM structure, and
getTargetRanges()data - Test with presets β Choose from 23+ sample HTML presets covering various scenarios (CJK, RTL, tables, code blocks, emoji, etc.)
- Export reports β Copy comprehensive event analysis reports for GitHub issues
Comprehensive guides covering all aspects of contenteditable:
- What is contenteditable? β Fundamentals, use cases, and when to use (or avoid) it
- Events β Deep dive into the event lifecycle (
beforeinput,input,compositionstart/update/end,selectionchange) and how they differ across browsers - IME & Composition β How input methods (Korean, Japanese, Chinese, etc.) interact with contenteditable, common issues, and solutions
- Selection API β Working with
SelectionandRangeobjects, common pitfalls, and reliable patterns - Range API β Advanced range manipulation, boundary detection, and cross-browser compatibility
- Clipboard API β Copy, paste, and clipboard event handling
- execCommand alternatives β Why
execCommandis deprecated and modern approaches (Input Events, Selection API, custom implementations) - Practical Patterns β Real-world patterns for building editors, with code examples
- Common Pitfalls & Debugging β Frequent mistakes and how to debug contenteditable issues
- Performance β Optimizing contenteditable performance for large documents
- Accessibility β Making contenteditable accessible to screen readers and keyboard navigation
- Browser compatibility β Detailed support matrix and known issues per browser
Building a rich text editor? You'll encounter questions like:
- "Why does Enter behave differently in Safari?" β Safari inserts
<div>while Chrome inserts<br>, breaking your formatting logic - "Why does my Korean IME lose characters on certain key combos?" β Composition events fire in different orders, causing character loss
- "Why does paste formatting vary between browsers?" β Chrome preserves HTML structure, Firefox strips it, Safari does something else entirely
- "Why does undo/redo break after programmatic DOM changes?" β The undo stack is cleared or doesn't include your changes, making undo/redo unreliable
- "Why does my selection disappear after I wrap text in a
<strong>tag?" β Selection restoration is inconsistent across browsers - "Why does typing in a table cell break the table structure?" β Table editing behavior varies dramatically between browsers
- "Why does my code block lose indentation when users type?" β Whitespace preservation in
<pre><code>is unreliable
These aren't theoreticalβthey're real issues developers face daily. Each one can take hours or days to debug, often requiring:
- Reproducing the issue in multiple browsers and OS combinations
- Understanding the event sequence by adding extensive logging
- Finding workarounds through trial and error or reading obscure forum posts
- Testing edge cases to ensure the workaround doesn't break other features
contenteditable.lab collects these "incidents" with:
- Exact reproduction steps so you can verify the issue immediately
- Environment details so you know if it affects your users
- Event logs showing the exact sequence of events
- Proven workarounds that have been tested across environments
- Related cases so you can see if similar issues exist in other environments
You don't have to rediscover these problems the hard way.
- Rich text editor developers β ProseMirror, Slate, Lexical, Tiptap users
- Web application developers β Anyone using
contenteditablein production - Browser engineers β Understanding cross-browser behavior differences
- Accessibility specialists β Documenting input method behaviors
- Curious developers β Learning how the web platform really works
Found a weird contenteditable behavior?
- Go to the Playground
- Select an appropriate sample HTML preset or use your own content
- Reproduce the issue and observe the event log, range visualizations, and DOM changes
- If an anomaly is detected, a snapshot will be automatically saved
- Click "π Copy report" to get a comprehensive event analysis
- Open an issue with your findings
Many cases need confirmation across different environments. Pick a case marked as "draft" and test it in your environment.
The UI supports multiple languages. See TRANSLATION.md for contribution guidelines.
Precision over assumptions. Each case documents exactly what happens, not what "should" happen according to specs.
Environment matters. The same code produces different results on Windows Chrome vs macOS Safari vs mobile browsers. We capture these differences.
Reproducibility is key. Every case includes steps to reproduce. If you can't reproduce it, we refine the case until you can.
Community-driven. No single person has tested every OS Γ Browser Γ IME combination. This catalog grows through collective documentation.
- Real-time event monitoring β Track
selectionchange,compositionstart/update/end,beforeinput, andinputevents - Visual range indicators β Color-coded overlays for selection (blue), composition (purple), beforeinput (orange), deleted areas (yellow), and added areas (green)
- DOM change tracking β Compare text node states before and after input events
- Invisible character detection β Visual markers for ZWNBSP, NBSP, line breaks, tabs, and other non-visible characters
- Automatic snapshot capture β Snapshots are saved when anomalies are detected, preserving full event context
- Comprehensive event logs β Detailed information including:
- Event timing and sequence
- DOM node structure and hierarchy
- Selection ranges and offsets
getTargetRanges()data frombeforeinputevents- Boundary detection (inline element boundaries)
- Sibling node information
- Sample HTML presets β 23+ presets covering:
- Language-specific IME testing (Korean, Japanese, Chinese, Thai, Vietnamese, Arabic, Hindi)
- Complex structures (nested inline, tables, code blocks)
- Edge cases (HTML entities, RTL/LTR mixed, emoji, empty elements, long text wrapping)
- Special characters and invisible characters
This project is built with modern web technologies chosen for performance, developer experience, and maintainability:
-
Astro β Static site generator that generates fast, SEO-friendly pages. Perfect for documentation sites with minimal JavaScript by default, while allowing React components where needed (like the Playground).
-
React β Used for interactive components, specifically the Playground where real-time event monitoring and visualization require dynamic updates. React's component model makes it easy to manage complex state (event logs, snapshots, visualizations).
-
Tailwind CSS β Utility-first CSS framework for rapid UI development. Enables consistent styling across the site and makes dark mode theming straightforward with CSS variables.
-
React Flow + Dagre β Graph visualization library for displaying relationships between cases, scenarios, tags, and environments. Dagre provides automatic layout algorithms so the graphs are readable without manual positioning.
-
TypeScript β Type safety across the entire codebase. Critical for maintaining correctness in a project with complex data structures (event logs, DOM snapshots, case metadata).
-
IndexedDB β Client-side database for storing Playground snapshots. Allows users to save and restore editor states with full event context, even after page reloads. Snapshots are stored locally and don't require server infrastructure.
# Clone the repository
git clone https://github.com/easylogic/contenteditable.git
cd contenteditable
# Install dependencies
pnpm install
# Start development server
pnpm devThe dev server runs at http://localhost:4321 with hot module replacement enabled.
pnpm devβ Start development server athttp://localhost:4321pnpm buildβ Build production site to./dist/pnpm previewβ Preview the production build locally before deployingpnpm astro ...β Run Astro CLI commands directly
src/
βββ components/ # Astro & React components
β βββ Playground.tsx # Interactive testing playground
β βββ ScenarioFlow.tsx # Graph visualization
β βββ ...
βββ content/ # Markdown content
β βββ cases/ # Individual case files
β βββ scenarios/ # Scenario files
βββ data/
β βββ presets/ # Sample HTML presets for Playground
βββ i18n/
β βββ translations.ts # UI translations for 7 languages
βββ pages/ # Route pages
β βββ cases/ # Case detail pages
β βββ scenarios/ # Scenario detail pages
β βββ docs/ # Documentation pages
β βββ [locale]/ # Localized routes
βββ styles/
βββ global.css # Global styles with CSS variables
See DEVELOPMENT.md for detailed development setup, content management, and deployment instructions.
The site is fully internationalized to serve a global audience of developers working with contenteditable across different languages and input methods.
- πΊπΈ English (default) β Primary language, all content available
- π°π· Korean β Full UI translation, important for Korean IME testing
- π―π΅ Japanese β Full UI translation, important for Japanese IME testing
- π¨π³ Chinese β Full UI translation, important for Chinese IME testing
- πͺπΈ Spanish β Full UI translation
- π©πͺ German β Full UI translation
- π«π· French β Full UI translation
- UI elements β Navigation, buttons, labels, tooltips
- Navigation β Menu items, breadcrumbs, page titles
- Documentation β All documentation pages are available in all languages
- Case and scenario content β Cases and scenarios can be written in any supported language
The site automatically detects the user's browser language and serves content in the appropriate locale. Users can also manually switch languages using the language selector in the navigation.
See TRANSLATION.md for detailed guidelines on:
- Adding new languages
- Translating UI strings
- Translating content (cases, scenarios, documentation)
- Maintaining translation quality
- π Live Site
- π Translation Guide
- π€ Contributing Guide
- π οΈ Development Guide
- π Report an Issue
- π¬ GitHub Discussions