Start with this HTML:
<div>click here</div>
<div style="user-select: none;">read-only (no-select)</div>
<div contenteditable style="user-select: none;">editable (no-select)</div>
<div>release here</div>
Click at the top ("click here") and drag down and release at the bottom ("release here"). The following text will be selected:
If you were to copy+paste, you would see the same:
click here
editable (no-select)
release here
Arguably the "editable (no-select)" text should not be included, since it is styled with user-select: none;
, but it is selected anyway. (FWIW I don't think this is crazy, since editing text often requires selecting it.)
Still, what if you wanted to preserve the text editable behavior while also excluding it from selection? You could try disabling it conditionally:
<div
id="target"
contenteditable="false"
style="user-select: none;"
tabindex="0"
/>
<script>
const target = document.getElementById('target');
// "focusin" behaves the same as "focus"
target.addEventListener('focus', () => {
target.setAttribute('contenteditable', true);
});
target.addEventListener('mousedown', () => {
target.setAttribute('contenteditable', true);
});
target.addEventListener('blur', () => {
target.setAttribute('contenteditable', false);
});
</script>
This approach almost works!
- ✅ Clicking into the item works; you can edit
- ✅ Tabbing (or clicking) out of it works; selection behavior is correct
- ❌ Tabbing into the item doesn't work; it receives focus and the attribute updates, but the text remains non editable
So how would you approach this? Any suggestions?
I believe the following might work.