Increasing Textual content Areas Made Elegant – A Checklist Aside

An increasing textual content space is a multi-line textual content enter area that expands in peak to suit its contents. This UI factor is usually present in each desktop and cell functions, such because the SMS composition area on the iPhone. Examples may also be discovered on the internet, together with on Fb, the place it’s used extensively. It’s a good selection wherever you don’t understand how a lot textual content the consumer will write and also you wish to preserve the structure compact; as such, it’s particularly helpful on interfaces focused at smartphones.

Article Continues Beneath

Regardless of the ubiquity of this management, there’s no option to create it utilizing solely HTML and CSS. Whereas regular block-level components (like a div, for instance) develop to suit their content material, the common-or-garden textarea doesn’t, even if you happen to fashion it as show: block. Since that is the one option to settle for multi-line consumer enter (apart from utilizing contenteditable, an entire world of ache I’m not going to dive into right now), just a little JavaScript is required to make it resize as desired.

Trawling the web, you will discover a number of makes an attempt at creating increasing textual content areas, however most undergo from a number of of the next issues:

  • The peak is calculated by guessing the place wrapping happens primarily based on the cols attribute. This breaks if you happen to set the width of the textarea in CSS, use a proportional width font, or just don’t provide a cols attribute.
  • The peak is recalculated and set solely on the keyup (and presumably reduce/paste) occasions. This doesn’t work if the textarea has a fluid width and the window is resized.
  • The required peak is calculated primarily based on the scrollHeight attribute, which isn’t laid out in any W3C spec (it was launched by IE) and thus unsurprisingly has delicate variations between implementations, requiring an inelegant and brittle lump of browser-sniffing code.

The perfect resolution I’ve seen makes use of a separate pre factor completely positioned off display, styled the identical because the textarea; let’s name this the mirror factor. Utilizing setTimeout, the textarea is then polled each 200ms or so, and every time a brand new worth is discovered, the content material of the mirror factor is up to date. This then robotically sizes to suit its content material (as a standard block-level factor does), after which you’ll be able to extract the dimensions from the offsetHeight property and apply that again to the textarea.

This technique works, however the polling is inefficient, particularly in case you have a number of textual content areas. Worse, if you happen to assist flexible-width textual content areas you need to test that the width of the textarea hasn’t modified on every ballot as properly (an costly learn to offsetWidth). It may be tough to calculate the precise width of the content-box within the textarea; therefore there’s usually a “fudge issue” added to the peak utilized to the textarea, simply to ensure it’s not barely too quick, leading to a field that’s then barely too huge for the content material. Right here, I’m going to point out you a greater resolution to the issue, which sizes the textarea utilizing solely the smallest snippet of JavaScript magic together with some crafty CSS.

The approach is an enchancment on the offscreen-positioned mirror factor. The primary enchancment we make is said to how we detect enter. The change occasion isn’t very best because it solely fires when the textarea loses focus. The keyup occasion works more often than not, but additionally fires on occasions the place no actual change has been made, resembling transferring the cursor left and proper; and it doesn’t hearth if the consumer makes use of the mouse to chop or paste. What we actually need is an occasion that merely fires each time the worth of the textarea adjustments. Luckily, such an occasion exists and it’s extremely helpful, though it’s talked about so not often it might appear many are unaware of its existence. The occasion is just referred to as enter, and you employ it similar to another occasion:

textarea.addEventListener('enter', perform (occasion) {
    /* Code to deal with occasion */
}, false );

So our first enchancment is to cease polling utilizing setTimeout and as an alternative use the way more environment friendly enter occasion. That is supported cross-browser, even in Web Explorer from model 9, though in fact there’s an IE bug: it doesn’t hearth if you delete textual content, so the world is not going to shrink till textual content is added once more. If this can be a concern you can too look ahead to the keyup occasion in IE to cowl most circumstances.

For IE8 we are able to use the proprietary onpropertychange occasion, which additionally fires each time the worth property adjustments. This occasion can also be accessible on variations lower than 8, however a number of small CSS tweaks will in all probability be wanted to make the increasing textual content space work general; I go away making it work in IE6 or IE7 as an train to the readers unfortunate sufficient to should assist these historical browsers.

Now, a few of you’ll have noticed that, as we’re now not polling, the textarea received’t resize if it has a fluid width and the window is resized. That brings us to our subsequent enchancment: we’re going to make the browser resize the textarea robotically. However, I hear you cry, I assumed you mentioned this was not possible? Effectively, not fairly. You possibly can’t do it robotically with simply HTML and CSS, however all of the JS must do is replace the mirror factor with the worth of the textarea. It doesn’t should measure or explicitly set peak. The trick is to place the textarea on high of the mirror factor, each inside a relatively-positioned containing div. The textarea is positioned completely and given a width and peak of 100% to make it fill the div. The mirror is positioned statically so it’s going to develop to suit its contents. The containing div will then develop to suit the peak of the mirror and this in flip will make the completely positioned textarea resize to fill the container, thus making it the right peak to suit its contents.

Sufficient rationalization, simply give me the code!#section2

Whoa there! I’m simply attending to that. It’s actually fantastically easy. The markup seems like this:

<div class="expandingArea">
  <pre><span></span><br></pre>
  <textarea></textarea>
</div>

The pre is our mirror. We want a br on the finish of it to make sure that any trailing whitespace copied from the textarea is rendered by the browser accurately and never chewed up. The span factor is due to this fact the one we truly replace with the contents of the textarea.

Now, the CSS. First, a tiny reset; (you in all probability have already got this):

textarea, 
pre {
  margin: 0;
  padding: 0;
  define: 0;
  border: 0;
}

Containing components have the expandingArea class. You possibly can outline any border or inset box-shadow and so forth., right here that you simply wish to use to fashion your textual content space. I’ve simply added a easy 1px stable grey border. You can even set a min-height property if you need and it’ll work as anticipated:

.expandingArea {
  place: relative;
  border: 1px stable #888;
  background: #fff;
}

You possibly can set any padding, line peak, and font kinds you want, simply be sure that they’re the identical for each the textarea and the pre factor:

.expandingArea > textarea,
.expandingArea > pre {
  padding: 5px;
  background: clear;
  font: 400 13px/16px helvetica, arial, sans-serif;
  /* Make the textual content soft-wrap */
  white-space: pre-wrap;
  word-wrap: break-word;
}
.expandingArea > textarea {
  /* The border-box field mannequin is used to permit
   * padding while nonetheless conserving the general width
   * at precisely that of the containing factor.
   */
  -webkit-box-sizing: border-box;
     -moz-box-sizing: border-box;
      -ms-box-sizing: border-box;
          box-sizing: border-box;
  width: 100%;
  /* This peak is used when JS is disabled */
  peak: 100px;
}
.expandingArea.energetic > textarea {
  /* Conceal any scrollbars */
  overflow: hidden;
  place: absolute;
  high: 0;
  left: 0;
  peak: 100%;
  /* Take away WebKit user-resize widget */
  resize: none;
}
.expandingArea > pre {
  show: none;
}
.expandingArea.energetic > pre {
  show: block;
  /* Conceal the textual content; simply utilizing it for sizing */
  visibility: hidden;
}

And lastly we use the next JavaScript. For brevity I’ve omitted the same old function detection you must do earlier than utilizing querySelector() or querySelectorAll(). In the very best custom of swish degradation, customers with out JavaScript enabled will get a hard and fast peak textarea (with the peak set within the CSS), with scrollbars showing when the content material overflows:

perform makeExpandingArea(container) {
 var space = container.querySelector('textarea');
 var span = container.querySelector('span');
 if (space.addEventListener) {
   space.addEventListener('enter', perform() {
     span.textContent = space.worth;
   }, false);
   span.textContent = space.worth;
 } else if (space.attachEvent) {
   // IE8 compatibility
   space.attachEvent('onpropertychange', perform() {
     span.innerText = space.worth;
   });
   span.innerText = space.worth;
 }
// Allow additional CSS
container.className += "energetic";
}var areas = doc.querySelectorAll('.expandingArea');
var l = areas.size;whereas (l--) {
 makeExpandingArea(areas[l]);
}

A word on delegation: you’ll be able to simply set this up with a single occasion listener on the doc node and use occasion delegation to deal with a number of increasing textual content areas effectively, however provided that you’re not supporting IE8 or beneath, as Microsoft, of their infinite knowledge, didn’t make the onpropertychange occasion bubble.

The compulsory demo#section3


Because of the method redraws are batched in Opera for Mac OS X, a slight flicker could happen when a brand new line is added to the textual content area. You possibly can work round this by at all times making it a line taller than it must be in Opera on Mac; simply add the next code to the highest of the makeExpandingArea perform (sadly there’s no option to do function detection for this):

if ( window.opera && /Mac OS X/.check( navigator.appVersion ) ) {
  container.querySelector( 'pre' )
           .appendChild(
    doc.createElement( 'br' )
  );
}

Lastly, as a result of the textarea is positioned instantly over the pre, you’ll be able to lengthen this to do funky stuff resembling syntax highlighting as you kind; if you happen to parse the worth and break up it into totally different tags earlier than including it to the pre, you’ll be able to apply totally different colours to totally different sections. You’ll must take away the visibility: hidden declaration from the pre and as an alternative add coloration: clear to the textarea. We use this system in My Opera Mail to make it simpler to scan the names within the To/Cc/Bcc fields of the compose display. The snag is that each one browsers apart from Opera make the cursor coloration the identical because the textual content coloration, so the cursor disappears if you make the colour clear. I don’t imagine any W3C normal covers this (please let me know if I’m flawed), however the platform normal (primarily based on the textual content editors shipped with them) appears to be the inverse of the background coloration on Home windows and at all times black on Mac, no matter background or foreground coloration. However till the opposite browsers see the sunshine and repair this habits you’ll be able to nonetheless apply the syntax highlighting on blur and switch it off whereas the consumer is definitely enhancing, or change the background coloration as an alternative.

And that’s it people! Hope you’ve loved studying this text and perhaps realized a helpful new approach. It’s elegant and environment friendly and works simply as properly in fashionable cell browsers as on the desktop. Comfortable hacking!

Leave a Comment