Is it possible to prevent child elements from being deleted when their parent is contentEditable?

Viewed 892

When an element is contentEditable, its child elements can be deleted. If one of those child elements is not contentEditable, the content of the child cannot be edited, but the element itself can still be deleted. You can see this demonstrated in the following example.

Is it possible to prevent these child elements from being deleted?

div {
  height: 100px;
  border: 1px solid #CCC;
  margin: 5px;
  padding: 5px;
  width: 300px;
}

span {
  color: #999;
}
<div contentEditable="true">Hello <span contentEditable="false">world</span>!</div>

2 Answers

If you can use classes, it would be easy.

<div class="contentEditable">Hello <span class="contentNotEditable">world</span>!</div>
<div class="saveContent" style="display: none;"></div>

Javascript/Jquery Part

<script>
$(".contentEditable").on("click",function(){
 // make blank .saveContent
 $(".saveContent").html("");

 // copy all contentNotEditable class which inside selected contentEditable class.
 $( this ).find(".contentNotEditable").clone().appendTo( ".saveContent" );

 // make blank contentEditable
 $( this ).html("");

 // clone contentNotEditable to contentEditable
 $( ".saveContent" ).find(".contentNotEditable").clone().appendTo( ".contentEditable" );
});
</script>

Is it possible to prevent these child elements from being deleted?

No, but here is an alternative solution.

Demo:

Since we can't have direct children, we need to create two separate elements.

<div class="editor">
  <label class="editor-label">You can't remove me</label>
  <div class="editor-area" contentEditable="true"></div>
</div>


Then, we remove label from the flow so it won't have any effects on area.

.editor {
  border: solid 1px #CCC;
  position: relative; // context for label
  line-height: 1.5;
}

.editor-area {
  min-height: 100px;
  padding: 5px;
}

.editor-label {
  position: absolute; // out of the flow
  padding: 5px 0 0 5px;
  user-select: none;
}


Finally, to make the caret start after the label text, we need to know its width and apply it to area's text-indent value.

var editorLabel = document.querySelector('.editor-label');
var editorArea = document.querySelector('.editor-area');

var editorLabelRect = editorLabel.getBoundingClientRect();

editorArea.style.textIndent = editorLabelRect.width + 'px';
editorArea.innerHTML = '&nbsp';

Complete code:

var editorLabel = document.querySelector('.editor-label');
var editorArea = document.querySelector('.editor-area');

var editorLabelRect = editorLabel.getBoundingClientRect();

editorArea.style.textIndent = editorLabelRect.width + 'px';
editorArea.innerHTML = '&nbsp';
.editor {
  border: solid 1px #CCC;
  position: relative;
  line-height: 1.5;
}

.editor-area {
  min-height: 100px;
  padding: 5px;
}

.editor-label {
  position: absolute;
  margin: 5px 0 0 5px;
  user-select: none;
}
<div class="editor">
  <label class="editor-label">You can't remove me</label>
  <div class="editor-area" contentEditable="true"></div>
</div>

Related