Events: change, input, cut, copy, paste
Every form is a conversation. The user types, deletes, pastes, picks from a dropdown, and your code needs to know when something happened so it can react — validate a field, mirror a value somewhere, sanitize pasted junk. The browser fires a small family of events for exactly these moments. The trick is knowing which one fires when, because they do not all agree on timing.
Two of them, change and input, cover ordinary edits. Three more — cut, copy, and paste — cover the clipboard. This lesson walks through all five and the security wall the clipboard hides behind.
Event: change
The change event fires when an element has finished changing. The word “finished” is doing a lot of work, because what counts as finished depends on the control.
For a text input, “finished” means the field lost focus. While you type, nothing fires. The event waits until you move on — click a button, press Tab, or click somewhere else on the page. Only then does the browser decide the edit is complete and fire change.
Type in the field below and watch: no alert appears while your cursor is inside it. Click the button (which pulls focus away) and the change event fires.
<input type="text" onchange="alert(this.value)">
<input type="button" value="Save">
Here it is live — no alert this time, just a counter. Type as much as you like into the field: the tally stays put. Only when you leave the field (click the button or click away) does change fire and the committed value appear.
Other controls behave differently. For a <select>, a checkbox, or a radio button, there is no drawn-out typing phase — the user makes a discrete choice. So change fires the instant the selection changes, no focus loss required.
<select onchange="alert(this.value)">
<option value="">Choose a size</option>
<option value="s">Small</option>
<option value="m">Medium</option>
<option value="l">Large</option>
</select>
Pick an option and the alert appears right away. Try both a dropdown and a checkbox below — each reports the instant you make the choice, with no need to click elsewhere first.
Event: input
The input event fires every time the value is modified by the user. Not on focus loss, not once at the end — on each modification, immediately.
Its strength is that it catches any value change, not only keyboard ones. Paste from the mouse’s right-click menu, drop text in, dictate with speech recognition — input fires for all of them, because all of them change the value. Keyboard events like keydown would miss the mouse paste entirely.
<input type="text" id="field"> oninput: <span id="echo"></span>
<script>
field.oninput = function() {
echo.innerHTML = field.value;
};
</script>
That handler mirrors the field into a <span> live, character by character. If you need to react to every edit — a live search box, a character counter, an as-you-type validator — input is the event you want.
The demo below does both jobs at once: it mirrors your text and counts characters on every modification. Notice it updates before you leave the field — that is the whole difference from change. Try pasting with the right-click menu too; the counter still moves.
The flip side of “fires on value change” is “fires only on value change.” Pressing an arrow key ⇦ ⇨ to move the cursor changes nothing about the value, so input stays quiet. Same for holding Shift or tapping Ctrl alone. If you need those, reach for keyboard events instead.
Events: cut, copy, paste
These three fire on the matching clipboard actions. They belong to the ClipboardEvent interface, whose defining feature is the event.clipboardData property — your window into what is being cut, copied, or pasted.
Because they are cancelable, event.preventDefault() inside a handler aborts the action outright. Prevent a paste and nothing lands in the field; prevent a copy and nothing reaches the clipboard.
The example below intercepts all three. It shows what the user tried to move, then blocks it:
<input type="text" id="field">
<script>
field.onpaste = function(event) {
alert("paste: " + event.clipboardData.getData('text/plain'));
event.preventDefault();
};
field.oncut = field.oncopy = function(event) {
alert(event.type + '-' + document.getSelection());
event.preventDefault();
};
</script>
Notice the asymmetry between paste and cut/copy, and why the code reads the data two different ways. See it for yourself below: select some words in the sentence and press Ctrl/Cmd + C, then click into the field and paste. On copy, getData comes back empty and getSelection() has the text; on paste, getData finally holds it.
- user hits Ctrl+C
- handler runs
clipboardData → “” (empty)
readdocument.getSelection() - browser writes to clipboard
- user hits Ctrl+V
- handler runs
clipboardData → “the text”
readgetData(‘text/plain’) - browser inserts into field
The clipboard is not limited to text. You can copy a file in your OS file manager and paste it into a page — and the paste handler will see it. That works because clipboardData implements the DataTransfer interface, the same object used for drag-and-drop. Its full set of methods (files, multiple data types, and so on) lives in the DataTransfer specification.
There is also a newer, asynchronous way to reach the clipboard: navigator.clipboard. It returns promises and works outside of event handlers, prompting the user for permission when needed. Details are in the Clipboard API and events specification. Historically its support has lagged in some browsers, so check compatibility before relying on it.
Safety restrictions
The clipboard is a shared, OS-level resource. A user hops between apps all day, copying passwords in one window and pasting into another. A random web page has no business reading all of that. So browsers wrap clipboard access in guardrails.
The core rule: seamless read and write access to the clipboard is granted only during genuine, user-initiated actions — the real cut, copy, and paste events triggered by the user. Outside that context, the door is closed.
A few consequences follow from that rule:
- Synthetic events don’t get access. Dispatching a fake clipboard event with
dispatchEventis blocked in every browser except Firefox. Even where a synthetic event can be dispatched, the specification requires that it expose no clipboard data. - You can’t stash it for later. Saving
event.clipboardDatain a handler and reading from it after the handler returns won’t work. The object is live only inside the user-initiated event.
In short, event.clipboardData is bound to the moment the user acted. The newer navigator.clipboard is designed for broader use and leans on an explicit permission prompt instead.
Summary
Here are the data-change events side by side.
| Event | When it fires | Notes to remember |
|---|---|---|
change |
A value was committed. | On text inputs, waits for focus loss. On select/checkbox/radio, fires right when the choice changes. |
input |
On every user modification of the value. | Immediate, unlike change. Catches non-keyboard edits (paste, speech). Can’t be canceled — the value already changed. |
cut / copy / paste |
The matching clipboard action. | Cancelable with preventDefault(). event.clipboardData reads the data — but it’s empty during cut/copy (use document.getSelection()). navigator.clipboard is the async alternative. |
A quick way to choose: reach for change when you care only about the final, settled value (a filter, a saved setting). Reach for input when you need to track edits as they happen (live preview, counter, instant validation). Reach for the clipboard events when you need to inspect, block, or transform what the user is copying and pasting.