Skip to main content

A clean simple cross browser editable div.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Simple Editable Div</title>
<style>
  div.textarea {
    border: solid 1px #ccc;
    border-radius: 4px;
    height: auto;
    line-height: 1.4;
    font-size: 14px;
    font-family: "Helvetica Neue", arial, sans-serif;
    width: 100%;
    transition: all 0.15s ease-in-out;
    width: 100%;
    transition: all 0.15s ease-in-out;
    overflow: auto;
    word-wrap: break-word;
    color: #2a2e2e;
    cursor: text;
    display: block;
    padding: 6px 10px 8px;
    min-height: 100px;
  }

  div.textarea:focus {
    outline: none;
    box-shadow: 0 0 8px rgba(230, 210, 180, 1);
    border-color: #aaa;
  }

  [contenteditable]:empty:not(:focus):before {
    color: #687a86;
    line-height: 30px;
    font-size: 18px;
    content: attr(aria-label);
    display: block; /* For Firefox */
  }
</style>
</head>
  <body>
    <div style="width: 800px">
      <div contenteditable="true" tabindex="0" role="textbox" aria-multiline="true" data-role="editable" class="textarea plaintext" aria-label="Join the discussion..." id="comment-div" data-target="message"></div>
      <input type="hidden" name="message" id="message" value="" />
      <button id="submit">Submit</button>
    </div>
</body>
<script>
var Haack = (function() {
  // NodeList foreach Polyfill
  if (window.NodeList && !NodeList.prototype.forEach) {
    NodeList.prototype.forEach = function(callback, thisArg) {
      thisArg = thisArg || window;
      for (var i = 0; i < this.length; i++) {
        callback.call(thisArg, this[i], i, this);
      }
    };
  }

  // Haack namespace object.
  return {
    ready: function(init) {
      if (document.readyState === "complete" || (document.readyState !== "loading" && !document.documentElement.doScroll)) {
        window.setTimeout(init);
      } else {
        var completed = function() {
          document.removeEventListener("DOMContentLoaded", completed);
          window.removeEventListener("load", completed);
          init();
        };
        document.addEventListener("DOMContentLoaded", completed);
        window.addEventListener("load", completed);
      }
    },
    get: function(elementId) {
      return document.getElementById(elementId);
    }
  };
})();

Haack.ready(function() {
  document.querySelectorAll("div[contenteditable].plaintext").forEach(function(editor) {
      // Set up the content editable div
      try {
        editor.contentEditable = "PLAINTEXT-ONLY";
      } catch (e) {
        // Firefox hack to prevent rich text from being pasted.
        editor.contentEditable = "true";
        editor.addEventListener("paste", function(e) {
          e.preventDefault();
          if (e.clipboardData && e.clipboardData.getData) {
            var text = e.clipboardData
              .getData("text/plain")
              .replace(/(?:\r\n|\r|\n)/g, "<br />");
            document.execCommand("insertHTML", false, text);
          } else if (window.clipboardData && window.clipboardData.getData) {
            var text = window.clipboardData.getData("Text");
            insertTextAtCursor(text);
          }
        });
      }
      var targetHiddenInput = Haack.get(editor.dataset.target);
      if (targetHiddenInput) {
        editor.oninput = e => {
          targetHiddenInput.value = e.target.innerText;
        };
      }
    });
});

Haack.ready(function() {
  Haack.get("submit").onclick = () => {
    alert('The value of the "message" input is ' + Haack.get("message").value);
  };
});
</script>
</html>