Skip to content

Instantly share code, notes, and snippets.

@tonyonodi
Last active July 11, 2025 15:24
Show Gist options
  • Save tonyonodi/c7af0bf46f03165b3215c137969f4d39 to your computer and use it in GitHub Desktop.
Save tonyonodi/c7af0bf46f03165b3215c137969f4d39 to your computer and use it in GitHub Desktop.
// Drop this into your console then call it with an input selector, a string, and a delay to have it automatically type for
// you. For demo videos and such.
async function fakeType(text, selectorString = '.cm-content', delay = 50) {
const element = document.querySelector(selectorString);
if (!element) {
console.error(`fakeType Error: Element with selector "${selectorString}" not found.`);
return Promise.reject(new Error(`Element with selector "${selectorString}" not found.`));
}
// Ensure the element can accept value (e.g., input, textarea)
// If it's not an input/textarea, this won't directly set 'value',
// but the events will still dispatch.
if (element.tagName === 'INPUT' || element.tagName === 'TEXTAREA') {
element.value = ''; // Clear existing content before typing
} else if (element.contentEditable === 'true') {
element.innerHTML = ''; // Clear content for contenteditable elements
}
// Focus the element to make it behave more like a real input
element.focus();
for (let i = 0; i < text.length; i++) {
const char = text[i];
const charCode = char.charCodeAt(0);
// Simulate keydown event
// Using 'key' for modern compatibility and 'keyCode' for broader support (though deprecated)
const keyDownEvent = new KeyboardEvent('keydown', {
key: char,
code: `Key${char.toUpperCase()}`, // Best guess for 'code' for alphabetical chars
keyCode: charCode, // Deprecated, but good for compatibility
bubbles: true,
cancelable: true
});
element.dispatchEvent(keyDownEvent);
// Update the element's value or content manually
if (element.tagName === 'INPUT' || element.tagName === 'TEXTAREA') {
element.value += char;
} else if (element.contentEditable === 'true') {
// For contenteditable elements, append text and move caret to end
const selection = window.getSelection();
const range = document.createRange();
element.appendChild(document.createTextNode(char));
range.selectNodeContents(element);
range.collapse(false); // Collapse to the end
selection.removeAllRanges();
selection.addRange(range);
} else {
// For other elements (e.g., div), just append text (might not be visible or interactive)
element.textContent += char;
}
// Simulate input event (crucial for frameworks and listeners reacting to value changes)
const inputEvent = new Event('input', {
bubbles: true,
cancelable: true
});
element.dispatchEvent(inputEvent);
// Simulate keyup event
const keyUpEvent = new KeyboardEvent('keyup', {
key: char,
code: `Key${char.toUpperCase()}`,
keyCode: charCode,
bubbles: true,
cancelable: true
});
element.dispatchEvent(keyUpEvent);
// Wait for the specified delay before typing the next character
await new Promise(resolve => setTimeout(resolve, delay));
}
// After typing is complete, dispatch a 'change' event if it's an input/textarea
if (element.tagName === 'INPUT' || element.tagName === 'TEXTAREA') {
const changeEvent = new Event('change', {
bubbles: true,
cancelable: true
});
element.dispatchEvent(changeEvent);
}
console.log(`fakeType: Typing complete for "${selectorString}"`);
return Promise.resolve();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment