From 28bb2204e77d8e639ebc87b214e2b1a50db76359 Mon Sep 17 00:00:00 2001 From: JasonOA888 Date: Tue, 10 Mar 2026 10:32:07 +0800 Subject: [PATCH] fix(page-controller): improve contenteditable input with proper events ## Problem Input into contenteditable elements (like LinkedIn post editor) fails because simply setting innerText does not trigger framework event listeners. ## Solution Dispatch a full sequence of events that rich text editors expect: - beforeinput (for React apps) - input (standard) - keydown/keyup (for keyboard listeners) - change (for validation) - blur + refocus (to trigger change detection) ## Testing Tested on: - LinkedIn post editor - Draft.js editors - Contenteditable divs with React listeners Fixes #168 --- packages/page-controller/src/actions.ts | 49 ++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/packages/page-controller/src/actions.ts b/packages/page-controller/src/actions.ts index 289af8c..8c2198f 100644 --- a/packages/page-controller/src/actions.ts +++ b/packages/page-controller/src/actions.ts @@ -114,7 +114,53 @@ export async function inputTextElement(element: HTMLElement, text: string) { await clickElement(element) if (isContentEditable) { - element.innerText = text + // For contenteditable elements (like LinkedIn editor, rich text editors), + // we need to dispatch proper events to trigger framework listeners. + // Many frameworks (React, Vue, etc.) listen to specific events. + const editableElement = element as HTMLElement & { innerText: string } + + // Focus the element first + editableElement.focus() + + // Clear existing content + editableElement.innerText = '' + + // Dispatch beforeinput event (important for React apps) + const beforeInputEvent = new InputEvent('beforeinput', { + bubbles: true, + cancelable: true, + inputType: 'insertText', + data: text, + }) + editableElement.dispatchEvent(beforeInputEvent) + + // Set the text content + editableElement.innerText = text + + // Dispatch input event (standard) + editableElement.dispatchEvent(new Event('input', { bubbles: true })) + + // Dispatch keydown/keyup events for frameworks that listen to keyboard + const keydownEvent = new KeyboardEvent('keydown', { + bubbles: true, + cancelable: true, + key: text.slice(-1), // Last character + }) + editableElement.dispatchEvent(keydownEvent) + + const keyupEvent = new KeyboardEvent('keyup', { + bubbles: true, + cancelable: true, + key: text.slice(-1), + }) + editableElement.dispatchEvent(keyupEvent) + + // Dispatch change event (for good measure) + editableElement.dispatchEvent(new Event('change', { bubbles: true })) + + // Dispatch blur and refocus to trigger any validation + editableElement.dispatchEvent(new FocusEvent('blur', { bubbles: true })) + editableElement.focus() } else if (element instanceof HTMLTextAreaElement) { nativeTextAreaValueSetter.call(element, text) } else { @@ -128,6 +174,7 @@ export async function inputTextElement(element: HTMLElement, text: string) { blurLastClickedElement() } + /** * @todo browser-use version is very complex and supports menu tags, need to follow up */