diff --git a/README.md b/README.md
index 23dec7a..4be8a5f 100644
--- a/README.md
+++ b/README.md
@@ -200,9 +200,9 @@ The 29 parity tools are 1:1 with `chrome-devtools-mcp`; the 4 superset tools (`p
| `click` | `Input.dispatchMouseEvent` | No implicit auto-wait/retry — resolves and acts once; re-snapshot between steps. |
| `hover` | `Input.dispatchMouseEvent` (`mouseMoved`) | Same single-shot model as `click`. |
| `drag` | `Input.dispatchMouseEvent` (press→move→release) | Synthetic mouse drag; native HTML5 DnD is approximated. |
-| `fill` | `Input.insertText` | Atomic paste-like commit, not per-character keystrokes. |
+| `fill` | `Input.insertText` | Atomic paste-like commit, not per-character keystrokes. For rich-text `contenteditable` editors (Lexical/ProseMirror/Slate), `click` the editor **first** so a trusted caret exists — see [recipe](docs/recipes/typing-into-contenteditable-editors.md). |
| `fill_form` | per field: `callFunctionOn` + `insertText` | Array of `{uid|selector,value}`; same insertText caveat. |
-| `type_text` | `Input.insertText` | Appends (does not clear first); insertText, not per-key. |
+| `type_text` | `Input.insertText` | Appends (does not clear first); insertText, not per-key. Same `contenteditable` caveat as `fill`. |
| `press_key` | `Input.dispatchKeyEvent` | Curated named-key table + single chars; not the full Puppeteer KeyInput enum. |
| `upload_file` | `DOM.setFileInputFiles` | Requires a resolvable `` (uid or selector). |
| `take_screenshot` | `Page.captureScreenshot` (+ layout metrics) | Clip scale fixed at 1. Full-page uses `captureBeyondViewport` + layout-metrics clip. |
@@ -223,6 +223,12 @@ The 29 parity tools are 1:1 with `chrome-devtools-mcp`; the 4 superset tools (`p
| `list_mocks` *(superset)* | `Runtime.evaluate` (liveness probe) | Lists active mock sessions with rules + hit counts; prunes sessions whose tab closed. |
| `clear_mocks` *(superset)* | `Fetch.disable` | Tears down the resolved target's mock session (or all with `all:true`). |
+## Recipes
+
+Longer-form notes on driver-vs-page gotchas that don't fit a table cell:
+
+- [Typing into rich-text `contenteditable` editors (Lexical, ProseMirror, Slate, Draft.js)](docs/recipes/typing-into-contenteditable-editors.md) — why `fill` silently no-ops or garbles text in a framework editor, and the trusted-click-then-`insertText` ordering that fixes it.
+
## How it's built
```
diff --git a/docs/recipes/typing-into-contenteditable-editors.md b/docs/recipes/typing-into-contenteditable-editors.md
new file mode 100644
index 0000000..228a7c4
--- /dev/null
+++ b/docs/recipes/typing-into-contenteditable-editors.md
@@ -0,0 +1,103 @@
+# Recipe: typing into rich-text `contenteditable` editors (Lexical, ProseMirror, Slate, Draft.js)
+
+**Problem.** You call `fill` / `type_text` (or set `.textContent` and dispatch an
+`input` event yourself) on a rich-text editor and the text either doesn't appear,
+appears duplicated/garbled, or appears but the editor's own autosave / change
+handlers never fire. Plain `` and `