Animate the height transition of contenteditable after a line of text is added (using shift+enter) or removed

Currently, the contenteditable attribute is being utilized on the <div> tag to enable autogrow functionality similar to a textbox. Additionally, there is an attempt to incorporate a height transition. While most aspects are functioning correctly, there is one issue - the animated height adjustment does not occur when deleting characters, specifically a line, unlike when adding new lines. My CSS knowledge is still limited.

.autogrow {
  border: 1px solid rgb( 0, 0, 0 );
  padding: 10px;
}
@keyframes line_insert {
  from {
    height: 0px;
  }
  to {
    height: 20px;
  }
}
.autogrow[contenteditable] > div {
  animation-duration: 250ms;
  animation-name: line_insert;
}
.autogrow[contenteditable] {
  overflow: hidden;
  line-height: 20px;
}
<div class="autogrow" contenteditable="true"></div>

When attempting to animate using Shift + Enter, it does not work; however, it functions correctly when only using Enter. The challenge lies in deleting lines and using the Shift + Enter combination to enter a new line.

How can this be resolved? Is there a way to achieve this using purely CSS, or would it require implementing a JavaScript function?

Answer №1

To address these challenges, I adopt a solution that does not rely solely on CSS animations/transitions, as I have encountered issues with them in the past. For instance, when using the CSS implementation, there is a noticeable bounce-back effect if the Enter key is pressed too quickly (you can slow down the animation to observe this).

https://i.sstatic.net/vwwLI.gif

Furthermore, different browsers handle new lines differently, with some adding

<div><br></div>
while others, like certain versions of Internet Explorer, only add <br>.

I have not managed to address all these issues through modification or found a single implementation that solves them all. Therefore, I have chosen not to alter the behavior of contenteditable at all, relying instead on the browser's default functionality and responding to events as needed.

We can avoid concerns about key events like Shift + Enter or actions like deletion, as the browser handles these natively.

My approach involves using two elements: one for the actual contenteditable and another for styling purposes. The styling element adjusts its height with animations/transitions based on the height of the contenteditable.

To achieve this, I monitor all events that could alter the height of a contenteditable. If the height of my styling element differs, I animate it accordingly.

const kAnimationSpeed = 125;
const kPadding = 10;

$('div[contenteditable]').on('blur keyup paste input', function() {
  const styleElement = $(this).prev();

  const editorHeight = $(this).height();
  const styleElementHeight = styleElement.height();

  if (editorHeight !== styleElementHeight - kPadding * 2) {
    styleElement.stop().animate({ height: editorHeight + kPadding * 2 }, kAnimationSpeed);
  }
});
.autogrowWrapper {
  position: relative;
}

.autogrow {
  border: 1px solid rgb(0, 0, 0);
  height: 40px; /* line-height + 2 * padding */
}

div[contenteditable] {
  outline: none;
  line-height : 20px;
  position: absolute;
  top: 10px; /* padding */
  left: 10px; /* padding */
  right: 10px; /* padding */
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="autogrowWrapper">
  <div class="autogrow"></div>
  <div contenteditable="true"></div>
</div>

Answer №2

It may seem a bit unconventional, but this method gets the job done.

Start by adjusting your CSS code:

.autogrow {
  border: 1px solid rgb( 0, 0, 0 );
  padding: 10px;
}
@keyframes line_insert {
  from {
    height: 0px;
  }
  to {
    height: 20px;
  }
}
.autogrow[contenteditable] > div {
  animation-duration: 250ms;
  animation-name: line_insert;
}
.autogrow[contenteditable] {
  overflow: hidden;
  line-height: 20px;
}

Next, implement this jQuery script to detect Shift + Enter events and insert a div each time they occur:

$(".autogrow").keydown(function(e){

    if (e.keyCode == 13 && e.shiftKey || e.keyCode == 13)
    {
       $(this).animate({height: $(this).height()+20},200);
                $(this).append('<div><br></div>');
    }
});

With these changes, your setup should be good to go.

Feel free to test it out on this fiddle: https://jsfiddle.net/wx38rz5L/582/

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Guide to combining two jQuery scripts that utilize distinct data types

Working collaboratively with Tomas, progress has been made on this issue. Here is the updated code: The purpose of this script is to send a query string to the server for parsing and database insertion. Upon successful completion of the class method, a 100 ...

Merging text and a JSON object to retrieve the information

Having some trouble with a JSON object and retrieving values. This is the syntax that works for getting the data I need. dataJSON.companies[0].fields.Internet.length I want to dynamically evaluate the object using a string variable, like this... var me ...

Reposition picture "overlays" additional HTML components

I am struggling with rotating an image by clicking on a button as the image overlaps the buttons. Can anyone provide guidance on how to achieve this without overlapping? For reference, here is my code and an example: here (http://jsfiddle.net/jj03b17n/5/) ...

Explore various queries and paths within MongoDB Atlas Search

I am currently working on developing an API that can return search results based on multiple parameters. So far, I have been able to successfully query one parameter. For example, here is a sample URL: http://localhost:3000/api/search?term=javascript& ...

Creating a responsive navigation bar with Bootstrap步 is simple and effective

Thank you for taking the time to review my current code. The main issue I am encountering pertains to the responsiveness of the navbar. Whenever I zoom in or out, certain elements tend to lose their alignment and aesthetic appeal. Specifically, the navbar ...

Detecting browser or tab closure in Node/Express Application: A comprehensive guide

As I'm developing a Node + Express MVC application, I am looking for a way to automatically shut down the Express server when the browser or tab is closed. While I know I can achieve this using a vanilla JS script with the 'beforeunload' eve ...

When utilizing Reactjs, accessing an element by its id becomes challenging when the element is nested within a map() function

Currently, I am encountering an issue related to reactjs. In my scenario, I have a requirement to compare the height of the screen with a specific div to determine its maximum width. The challenge lies in the fact that the particular div I need to analyz ...

Display Bootstrap modal upon page load automatically

Is there a way to automatically trigger the Bootstrap model upon page load? I attempted implementing the following code in my index file: <script type="text/javascript> $(window).load(function () { $('#myModal').modal('sh ...

Utilizing Font Awesome icons within a JSON structure

I'm running into a bit of trouble trying to display font awesome icons. The text is written in json using a rakefile, and I'm attempting to insert a font awesome icon within the text. However, I'm facing difficulties because the text is in j ...

What to do when faced with the error message "Nodemon is not recognized as a command"?

When I try to run npm start, my Node.js is not starting. The error message displayed is: 'nodemon' is not recognized as an internal or external command, operable program or batch file. I have double-checked my environment path and also tried r ...

Displaying the servlet response within an iframe

This is the content of Content.jsp <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> &l ...

Transmitting and receiving a blob using JavaScript

Is there a way to send a blob using a JQuery ajax request and receive it server-side with Node.js + express? I tried sending the blob as a JSON string, but it doesn't seem to include any of the binary data: {"type":"audio/wav","size":344108} Are th ...

What is the best way to send {...rest} properties to a text field in react material?

When using a material textfield inside a wrapper component and passing the remaining props as {...otherprops} in a JavaScript file, everything works fine. However, when attempting to do the same in TypeScript, an error occurs. const TextFieldWrapper = (pro ...

What could be causing the PAGE CSS to malfunction?

I am looking to export HTML text as a word document with A4 size and portrait orientation. My JavaScript currently allows me to export the text, but it appears like a webpage format rather than in A4 or portrait mode. I have tried adding @page CSS styling ...

Guide on adding increasing numbers to Slug with Mongoose

Currently, I am working on a nodejs project using mongoose. My goal is to ensure that when I save a "slug" into the database, it checks if the slug already exists and adds a counter to it before saving. This means that if I have slugs like my-title, my-tit ...

One jQuery plugin was functioning perfectly, while the other one was failing to work as expected

I am working on a simple HTML file that includes a heading and two empty div elements. <h1>Blablabla.</h1> <div id="div1"></div> <div id="div2"></div> These two divs need to be populated with SVG content generated usin ...

What is the best way to upload this HTML file to create my own visual representation?

Feeling a bit unsure about which way to go for this problem, I don't have many options at the moment. Lately, I've been diving into Deep Learning and I'm interested in experimenting with Stanford's CS231N's Convolutional Neural Ne ...

Is there a performance boost when using queue() and filter() together in jQuery?

I'm currently refactoring some Jquery code and I've heard that chaining can improve performance. Question: Does this also apply to chains involving queue() and filter()? For instance, here is the un-chained version: var self = this, co = ...

Utilizing Next.js routing to accommodate two distinct subdomains on a single website

I am looking to develop a new platform using Next.js (React.js and React-router). The platform will have two distinct spaces - one for users and another for the owner to manage all users. To achieve this, I plan on splitting both areas into two subdomains: ...

Encountering a Rails 500 server error when making an Ajax request to a form_for partial

As part of my blog creation process, I am working on implementing a dashboard feature where users can easily select "New" from the side menu to bring up a form for creating a new article. To achieve this functionality, I have been experimenting with usin ...