javascript – contenteditable change events

The Question :

385 people think this question is useful

I want to run a function when a user edits the content of a div with contenteditable attribute. What’s the equivalent of an onchange event?

I’m using jQuery so any solutions that uses jQuery is preferred. Thanks!

The Question Comments :

The Answer 1

340 people think this answer is useful

I’d suggest attaching listeners to key events fired by the editable element, though you need to be aware that keydown and keypress events are fired before the content itself is changed. This won’t cover every possible means of changing the content: the user can also use cut, copy and paste from the Edit or context browser menus, so you may want to handle the cut copy and paste events too. Also, the user can drop text or other content, so there are more events there (mouseup, for example). You may want to poll the element’s contents as a fallback.

UPDATE 29 October 2014

The HTML5 input event is the answer in the long term. At the time of writing, it is supported for contenteditable elements in current Mozilla (from Firefox 14) and WebKit/Blink browsers, but not IE.


document.getElementById("editor").addEventListener("input", function() {
    console.log("input event fired");
}, false);
<div contenteditable="true" id="editor">Please type something in here</div>


The Answer 2

193 people think this answer is useful

Here is a more efficient version which uses on for all contenteditables. It’s based off the top answers here.

$('body').on('focus', '[contenteditable]', function() {
    const $this = $(this);
    $'before', $this.html());
}).on('blur keyup paste input', '[contenteditable]', function() {
    const $this = $(this);
    if ($'before') !== $this.html()) {
        $'before', $this.html());

The project is here:

The Answer 3

54 people think this answer is useful

Consider using MutationObserver. These observers are designed to react to changes in the DOM, and as a performant replacement to Mutation Events.


  • Fires when any change occurs, which is difficult to achieve by listening to key events as suggested by other answers. For example, all of these work well: drag & drop, italicizing, copy/cut/paste through context menu.
  • Designed with performance in mind.
  • Simple, straightforward code. It’s a lot easier to understand and debug code that listens to one event rather than code that listens to 10 events.
  • Google has an excellent mutation summary library which makes using MutationObservers very easy.


  • Requires a very recent version of Firefox (14.0+), Chrome (18+), or IE (11+).
  • New API to understand
  • Not a lot of information available yet on best practices or case studies

Learn more:

  • I wrote a little snippet to compare using MutationObserers to handling a variety of events. I used balupton’s code since his answer has the most upvotes.
  • Mozilla has an excellent page on the API
  • Take a look at the MutationSummary library

The Answer 4

22 people think this answer is useful

non jQuery quick and dirty answer:

function setChangeListener (div, listener) {

    div.addEventListener("blur", listener);
    div.addEventListener("keyup", listener);
    div.addEventListener("paste", listener);
    div.addEventListener("copy", listener);
    div.addEventListener("cut", listener);
    div.addEventListener("delete", listener);
    div.addEventListener("mouseup", listener);


var div = document.querySelector("someDiv");

setChangeListener(div, function(event){

The Answer 5

21 people think this answer is useful

I have modified lawwantsin ‘s answer like so and this works for me. I use the keyup event instead of keypress which works great.

$('#editor').on('focus', function() {
  before = $(this).html();
}).on('blur keyup paste', function() { 
  if (before != $(this).html()) { $(this).trigger('change'); }

$('#editor').on('change', function() {alert('changed')});

The Answer 6

11 people think this answer is useful

Two options:

1) For modern (evergreen) browsers: The “input” event would act as an alternative “change” event.

document.querySelector('div').addEventListener('input', (e) => {
    // Do something with the "change"-like event


<div oninput="someFunc(event)"></div>

or (with jQuery)

$('div').on('click', function(e) {
    // Do something with the "change"-like event

2) To account for IE11 and modern (evergreen) browsers: This watches for element changes and their contents inside the div.

var div = document.querySelector('div');
var divMO = new window.MutationObserver(function(e) {
    // Do something on change
divMO.observe(div, { childList: true, subtree: true, characterData: true });

The Answer 7

7 people think this answer is useful

const p = document.querySelector('p')
const result = document.querySelector('div')
const observer = new MutationObserver((mutationRecords) => {
  result.textContent = mutationRecords[0]
  // result.textContent = p.textContent
observer.observe(p, {
  characterData: true,
  subtree: true,
<p contenteditable>abc</p>
<div />

The Answer 8

3 people think this answer is useful

Here’s what worked for me:

   var clicked = {} 
        var id = $(this).attr("id");
        $(this).bind('focus', function() {
            // store the original value of element first time it gets focus
            if(!(id in clicked)){
                clicked[id] = $(this).html()

   // then once the user clicks on save
            for(var id in clicked){
                var original = clicked[id];
                var current = $("#"+id).html();
                // check if value changed
                if(original != current) save(id,current);

The Answer 9

3 people think this answer is useful

This thread was very helpful while I was investigating the subject.

I’ve modified some of the code available here into a jQuery plugin so it is in a re-usable form, primarily to satisfy my needs but others may appreciate a simpler interface to jumpstart using contenteditable tags.


Due to its increasing popularity the plugin has been adopted by

Development will continue from here:

The Answer 10

2 people think this answer is useful

To avoid timers and “save” buttons, you may use blur event wich fires when the element loses focus. but to be sure that the element was actually changed (not just focused and defocused), its content should be compared against its last version. or use keydown event to set some “dirty” flag on this element.

The Answer 11

2 people think this answer is useful

Here is the solution I ended up using and works fabulously. I use $(this).text() instead because I am just using a one line div that is content editable. But you may also use .html() this way you dont have to worry about the scope of a global/non-global variable and the before is actually attached to the editor div.

$('body').delegate('#editor', 'focus', function(){
    $(this).data('before', $(this).html());
$('#client_tasks').delegate('.task_text', 'blur', function(){
    if($(this).data('before') != $(this).html()){
        /* do your stuff here - like ajax save */
        alert('I promise, I have changed!');

The Answer 12

1 people think this answer is useful

A simple answer in JQuery, I just created this code and thought it will be helpful for others too

    var cont;

    $("div [contenteditable=true]").focus(function() {

    $("div [contenteditable=true]").blur(function() {
        if ($(this).html()!=cont) {
           //Here you can write the code to run when the content change

The Answer 13

1 people think this answer is useful

Non JQuery answer…

function makeEditable(elem){
    elem.setAttribute('contenteditable', 'true');
    elem.addEventListener('blur', function (evt) {

To use it, call on (say) a header element with id=”myHeader”


That element will now be editable by the user until it loses focus.

The Answer 14

0 people think this answer is useful

The onchange event doesn’t fires when an element with the contentEditable attribute is changed, a suggested approach could be to add a button, to “save” the edition.

Check this plugin which handles the issue in that way:

The Answer 15

0 people think this answer is useful

Using DOMCharacterDataModified under MutationEvents will lead to the same. The timeout is setup to prevent sending incorrect values (e.g. in Chrome I had some issues with space key)

var timeoutID;
$('[contenteditable]').bind('DOMCharacterDataModified', function() {
    $that = $(this);
    timeoutID = setTimeout(function() {
    }, 50)
$('[contentEditable]').bind('change', function() {

JSFIDDLE example

The Answer 16

0 people think this answer is useful

I built a jQuery plugin to do this.

(function ($) {
    $.fn.wysiwygEvt = function () {
        return this.each(function () {
            var $this = $(this);
            var htmlold = $this.html();
            $this.bind('blur keyup paste copy cut mouseup', function () {
                var htmlnew = $this.html();
                if (htmlold !== htmlnew) {

You can simply call $('.wysiwyg').wysiwygEvt();

You can also remove / add events if you wish

The Answer 17

0 people think this answer is useful

In Angular 2+

<div contentEditable (input)="type($event)">

export class ContentEditableComponent {


 type(event) {
   console.log( // <-- The pressed key
   console.log(event.path[0].innerHTML) // <-- The content of the div 

The Answer 18

-1 people think this answer is useful

Check this idea out.

I think it’s close. HTML 5 really needs to add the change event to the spec. The only problem is that the callback function evaluates if (before == $(this).html()) before the content is actually updated in $(this).html(). setTimeout don’t work, and it’s sad. Let me know what you think.

The Answer 19

-2 people think this answer is useful

Based on @balupton’s answer:

$(document).on('focus', '[contenteditable]', e => {
	const self = $('before', self.html())
$(document).on('blur', '[contenteditable]', e => {
	const self = $(
	if ('before') !== self.html()) {
<script src=""></script>

Add a Comment