Prevent line/paragraph breaks in contentEditable
Asked Answered
I

13

75

When using contentEditable in Firefox, is there a way to prevent the user from inserting paragraph or line breaks by pressing enter or shift+enter?

Imperceptive answered 8/1, 2009 at 18:7 Comment(0)
D
87

You can attach an event handler to the keydown or keypress event for the contentEditable field and cancel the event if the keycode identifies itself as enter (or shift+enter).

This will disable enter/shift+enter completely when focus is in the contentEditable field.

If using jQuery, something like:

$("#idContentEditable").keypress(function(e){ return e.which != 13; });

...which will return false and cancel the keypress event on enter.

Dishman answered 9/1, 2009 at 14:3 Comment(4)
Note that this won’t work when copy-pasting text with line breaks into the contentEditable area.Jackboot
Does not cover the cases for pasting (from clipboard) or dropping content.Revile
it will be useful to handle multiple contenteditable elements on page, but not just oneFootless
@SystemsRebooter Just do it on different elements or use a loopBryantbryanty
O
55

This is possible with Vanilla JS, with the same effort:

document.getElementById('idContentEditable').addEventListener('keypress', (evt) => {
    if (evt.which === 13) {
        evt.preventDefault();
    }
});

You should not use jQuery for the most simple things. Also, you may want to use "key" instead of "which": https://developer.mozilla.org/en-US/docs/Web/Events/keypress

Update, since keypress is deprecated:

document.getElementById('idContentEditable').addEventListener('keydown', (evt) => {
    if (evt.keyCode === 13) {
        evt.preventDefault();
    }
});
Ornament answered 20/10, 2015 at 14:50 Comment(6)
I agree, and FWIW I wasn’t using JQuery in the project that prompted this question. It does annoy me a bit that JavaScript answers on SO usually assume everyone uses JQuery, but OTOH beginners are overwhelmingly likely to be using JQuery and everyone else is capable of translating the answers to use their preferred libraries or lack thereof :).Imperceptive
i do see it as a big problem that beginners always try to use jquery for everything. they don´t even really learn vanilla js anymore.Ornament
Now keyCode is deprecated too so use evt.key === "Enter". Can't speak to backwards compatibility here. Docs.Scrivner
And in the jquery flavor: $(".<class_name>").keypress(function(e) { if (e.which === 13) e.preventDefault(); });Teofilateosinte
There is a typo: evt.preventDefault should be event.preventDefault! Besides, the lambda syntax does not work in every browser. This code worked for me: name.addEventListener( 'keydown', function( event ) { if ( event.keyCode === 13 ) { event.preventDefault(); } } );Papistry
do you mean the arrow function? because it works in every important browser: caniuse.com/#feat=arrow-functions - IE11 has no real relevance anymore. you are right about the typo though, thanx for pointing it out!Ornament
D
23

Add the following CSS rule to hide line breaks. This is only a style setting, you should add some event handlers to prevent inserting line breaks:

.your_editable br {
    display: none
}
Dudden answered 25/8, 2013 at 7:32 Comment(3)
Chrome inserts some <DIV>s too, so might add .your_editable * { display: inline } before that.Soggy
Annoying, indeedBryantbryanty
What a unique approach. I had an unrelated issue where the custom-styled text used to move up due to the chrome-inserted line break's deletion. Interestingly the problem resolved itself by refreshing the stylesheet from the dev tools. I lost hope until I found your solution. It works now.Evert
U
12

Other than adding line breaks, the browser adds additional tags and styles (when you paste text, the browser also appends your pasted text style).

The code below covers it all.

  • When you press enter, no line breaks will be added.
  • When you paste text, all elements added by the browser are stripped from the text.

    $('[contenteditable]').on('paste', function(e) {
        //strips elements added to the editable tag when pasting
        var $self = $(this);
        setTimeout(function() {$self.html($self.text());}, 0);
    }).on('keypress', function(e) {
         //ignores enter key
         return e.which != 13;
    });
    

Click here for a live example

Underarm answered 24/5, 2017 at 14:56 Comment(1)
From review queue: May I request you to please add some context around your source-code. Code-only answers are difficult to understand. It will help the asker and future readers both if you can add more information in your post.Drypoint
P
7

another option is to allow breaks to be entered but remove them on blur. this has the advantage of dealing with pasted content. your users will either love it or hate it (depending on your users).

function handle_blur(evt){
  var elt=evt.target; elt.innerText=elt.innerText.replace(/\n/g,' ');
}

then, in html:

<span onblur="handle_blur(event)" contenteditable>editable text</span>
Peanut answered 10/1, 2013 at 19:50 Comment(0)
C
6

If you are using JQuery framework, you can set it with the on method which will let you have the desired behavior on all elements even if this one is added lately.

$(document).on('keypress', '.YourClass', function(e){
    return e.which != 13; 
});   
Capernaum answered 20/12, 2012 at 15:48 Comment(0)
A
6

Add:

display: flex;

On the contenteditable html element

Alternation answered 1/3, 2020 at 6:14 Comment(5)
Please add a proper explanation of how your solution addresses the question.Finkle
Simple yet perfect!Dualistic
nice one and perfect !Detrition
Does not work when using shift+enterSupralapsarian
This works in the following way: When you add a line break in a content editable element, the browser automatically wraps your lines inside a div element. When the line breaks, it adds a div element automatically to start the current new line. By using display: flex, you make the DIVs appear horizontally in the same line, unlike display: block which is applied by default. This does not prevent the addition of new lines. It just makes them appear directly next to each other. You could confirm this behavior by using the DevTools or pressing shift+enter.Supralapsarian
B
3
$("#idContentEditable").keypress(function(e){ return e.which != 13; });

Solution proposed by Kamens doesn't work in Opera, you should attach event to document instead.

/**
 * Pass false to enable
 */
var disableEnterKey = function(){
    var disabled = false;

    // Keypress event doesn't get fired when assigned to element in Opera
    $(document).keypress(function(e){
        if (disabled) return e.which != 13;
    });                 

    return function(flag){
        disabled = (flag !== undefined) ? flag : true;
    }
}();    
Brash answered 26/2, 2009 at 13:51 Comment(0)
M
3

If you want to target all the contentEditable fields use

$('[contenteditable]').keypress(function(e){ return e.which != 13; });
Moo answered 28/7, 2015 at 20:13 Comment(0)
D
2

I came here searching for the same answer, and was surprised to find it's a rather simple solution, using the tried and true Event.preventDefault()

const input = document.getElementById('input');

input.addEventListener('keypress', (e) => {
  if (e.which === 13) e.preventDefault();
});
<div contenteditable="true" id="input">
  You can edit me, just click on me and start typing.
  However, you can't add any line breaks by pressing enter.
</div>
Denysedenzil answered 29/11, 2018 at 13:17 Comment(2)
that´s exactly my answer, 3 years before yours ;)Ornament
Ah, so it is, not sure why I answered this question then, perhaps it didn’t have an accepted answer, and I didn’t see your reply; however, there is one key difference, I assigned the element to a const to make the code more readable #mindblowingDenysedenzil
H
2

Use the beforeinput event and when you hear the event and it has an inputType of either insertParagraph (Enter) or insertLineBreak (Shift+Enter) you can simply cancel the event using event.preventDefault() and use event.stopPropagation() to stop the event from getting propagated to other event listeners.

You can test this yourself using this HTML:

<html>
<body>
<p>Write in the contentEditable div below!</p>
<div contentEditable="true" style="width:100%;height:200px;border:1px solid black;"></div>
<script>
  document.addEventListener('beforeinput', event => {
    const {
      dataTransfer,
      inputType,
      isComposing,
      data,
    } = event;

    if (dataTransfer) {
      console.log('dataTransfer.getData(text/html) ===', printR(dataTransfer.getData('text/html')));
      console.log('dataTransfer.getData(text/plain) ===', printR(dataTransfer.getData('text/plain')));
    }

    const convertToRange = staticRange => {
      if (staticRange instanceof StaticRange) {
        const {
          startContainer, startOffset,
          endContainer, endOffset,
        } = staticRange;
        const range = document.createRange();
        range.setStart(startContainer, startOffset);
        range.setEnd(endContainer, endOffset);
        return range;
      }
    };

    // Get the static ranges that will be affected by a change to the DOM if the input event is not canceled
    const ranges = event.getTargetRanges?.() || [];
    ranges.forEach(staticRange => {
      const range = convertToRange(staticRange);
      console.log(`Range text content: "${range}"`);
    });
    console.log('ranges.length ==', ranges.length);

    console.log('The "inputbefore" event was detected! event ==', {
      dataTransfer,
      inputType,
      isComposing,
      data,
    });

    if (['insertParagraph', 'insertLineBreak'].includes(inputType)) {
      console.log('CANCELING event with inputType ==', inputType);
      event.preventDefault();
      event.stopPropagation();
    }
  });
</script>
</body>
</html>

When you press Enter (or Shift+Enter) you should notice nothing changing inside the <div contentEditable="true"> element.

Hippocrates answered 25/3, 2023 at 14:46 Comment(2)
What are the roles played respectively by stopPropagation() and preventDefault() ? EDIT : After doing some tests, it seems like preventDefault() is doing the work fo actually preventing input while stopPropagation probably juste prevents other event listeners to be firedYvoneyvonne
@Yvoneyvonne That is correct. I've edited my answer to clarify.Hippocrates
T
1

In the KeyboardEvent interface e.which and e.keyCode are deprecated and have been replaced by e.key.

A list of possible values for e.key can be found here on MDN or here on W3.

To prevent possibility of typing a new line or a tab which would exit the input consider the following for react/next:

onKeyDown = {(e) => {
  return ["Enter", "Tab"].includes(e.key) ? e.preventDefault() : null
}}
Term answered 25/11, 2023 at 16:8 Comment(0)
S
-5

Use CSS:

word-break: break-all;

For me, its worked!

Superstar answered 2/8, 2018 at 14:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.