Image may be NSFW.
Clik here to view.
An expanding ease area is a multi-line ease contention domain that expands in tallness to fit a contents. This UI member is customarily found in both desktop and mobile applications, such as a SMS multiple domain on a iPhone. Examples can also be found on a web, including on Facebook, where it’s used extensively. It’s a good choice wherever we don’t know how many ease a user will write and we wish to keep a plans compact; as such, it’s generally useful on interfaces targeted during smartphones.
Despite a ubiquity of this control, there’s no proceed to emanate it controlling customarily HTML and CSS. While normal block-level elements (like a div
, for example) raise to fit their content, a common textarea
does not, even if we impression it as display: block
. Since this is a customarily proceed to accept multi-line user contention (other than controlling contenteditable, a whole star of pain I’m not going to dive into today), a small JavaScript is indispensable to make it resize as desired.
Trawling a internet, we can find several attempts during formulating expanding ease areas, yet many humour from one or some-more of a following problems:
- The tallness is distributed by guessing where coupler occurs shaped on a
cols
attribute. This breaks if we set a extent of atextarea
in CSS, use a proportional extent font, or simply don’t supply acols
attribute. - The tallness is recalculated and set customarily on a
keyup
(and presumablycut
/paste
) events. This doesn’t work if atextarea
has a glass extent and a window is resized. - The mandatory tallness is distributed shaped on a
scrollHeight
attribute, that is not specified in any W3C spec (it was introduced by IE) and so unsurprisingly has forked differences between implementations, requiring an ungainly and frail raise of browser-sniffing code.
The best fortitude I’ve seen uses a detached pre
member definitely positioned off screen, styled a same as a textarea
; let’s call this a mirror element. Using setTimeout
, a textarea
is thereafter polled any 200ms or so, and any time a new value is found, a ease of a reflection member is updated. This thereafter automatically sizes to fit a ease (as a normal block-level member does), after that we can disturb a stretch from a offsetHeight
ability and ask that behind to a textarea
.
This routine works, yet a polling is inefficient, generally if we have churned ease areas. Worse, if we support flexible-width ease areas we strait check that a extent of a textarea
hasn’t altered on any check as good (an dear examination to offsetWidth
). It can be machiavellian to calculate a accurate extent of a content-box in a textarea
; hence there’s customarily a “fudge factor” total to a tallness unsentimental to a textarea
, customarily to make certain it’s not rather too short, indirect in a box that’s thereafter rather too vast for a content. Here, I’m going to expose we a softened fortitude to a problem, that sizes a textarea
controlling customarily a smallest lurch of JavaScript incantation along with some deception CSS.
The technique is an alleviation on a offscreen-positioned reflection element. The initial alleviation we make is compared to how we detect input. The change
eventuality is not ideal as it customarily fires when a textarea
loses focus. The keyup
eventuality works many of a time, yet also fires on events where no genuine change has been made, such as relocating a cursor left and right; and it does not heat if a user uses a rodent to cut or paste. What we unquestionably wish is an eventuality that simply fires whenever a value of a textarea
changes. Fortunately, such an eventuality exists and it’s impossibly useful, nonetheless it’s mentioned so bulk it would seem many are unknowingly of a existence. The eventuality is simply called input
, and we use it customarily like any other event:
textarea.addEventListener('input', avocation (event) { /* Code to hoop eventuality */ }, feign );
So a initial alleviation is to stop polling controlling setTimeout
and instead use a many some-more fit input
event. This is inspected cross-browser, even in Internet Explorer from account 9, nonetheless of impetus there is an IE bug: it doesn’t heat when we remove text, so a area will not tremble until ease is total again. If this is a courtesy we can also watch for a keyup
eventuality in IE to cover many cases.
For IE8 we can use a disdainful onpropertychange
event, that also fires whenever a value
ability changes. This eventuality is also permitted on versions rebate than 8, yet a few small CSS tweaks will almost be indispensable to make a expanding ease area work overall; we leave origination it work in IE6 or IE7 as an use to a readers unpropitious adequate to have to support those ancient browsers.
Now, some of we competence have speckled that, as we’re no longer polling, a textarea
won’t resize if it has a glass extent and a window is resized. That brings us to a successive improvement: we’re going to make a browser resize a textarea
automatically. But, we hear we cry, we guess we conspicuous this was impossible? Well, not quite. You can’t do it automatically with customarily HTML and CSS, yet all a JS needs to do is remodel a reflection member with a value of a textarea
. It doesn’t have to bulk or definitely set height. The fake is to position a textarea
on tip of a reflection element, both inside a relatively-positioned containing div
. The textarea
is positioned definitely and given a extent and tallness of 100% to make it fill a div
. The reflection is positioned statically so it will raise to fit a contents. The containing div
will thereafter raise to fit a tallness of a reflection and this in spin will make a definitely positioned textarea
resize to fill a container, so origination it a ideal tallness to fit a contents.
Enough explanation, customarily give me a code!
Whoa there! I’m customarily stealing to that. It’s unquestionably beautifully simple. The markup looks like this:
div class="expandingArea" prespan/spanbr/pre textarea/textarea /div
The pre
is a mirror. We need a br
during a finish of it to guarantee that any trailing whitespace copied from a textarea
is rendered by a browser righteously and not chewed up. The span
member is therefore a one we indeed remodel with a hint of a textarea
.
Now, a CSS. First, a small reset; (you almost already have this):
textarea, pre { margin: 0; padding: 0; outline: 0; border: 0; }
Containing elements have a expandingArea
class. You can interpretation any extent or inset box-shadow etc., here that we wish to use to impression your ease area. I’ve customarily total a facile 1px plain gray border. You can also set a min-height ability if we wish and it will work as expected:
.expandingArea { position: relative; border: 1px plain background: }
You can set any padding, line height, and arise styles we like, customarily make certain they’re a same for both a textarea
and a pre
element:
.expandingArea textarea, .expandingArea pre { padding: 5px; background: transparent; font: 400 13px/16px helvetica, arial, sans-serif; /* Make a ease soft-wrap */ white-space: pre-wrap; word-wrap: break-word; }.expandingArea textarea { /* The border-box box denote is used to concede * stuffing while still retaining a altogether breadth * during accurately that of a containing element. */ -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box; width: 100%; /* This tallness is used when JS is noxious */ height: 100px; }
.expandingArea.active textarea { /* Hide any scrollbars */ overflow: hidden; position: absolute; top: 0; left: 0; height: 100%; /* Remove WebKit user-resize widget */ resize: none; }
.expandingArea pre { display: none; } .expandingArea.active pre { display: block; /* Hide a text; customarily controlling it for sizing */ visibility: hidden; }
And lastly we use a following JavaScript. For abruptness I’ve wanting a common underline display we should do before controlling querySelector()
or querySelectorAll()
. In a best tradition of apt degradation, users yet JavaScript enabled will get a firm tallness textarea
(with a tallness set in a CSS), with scrollbars appearing when a ease overflows:
function makeExpandingArea(container) { var area = container.querySelector('textarea'); var cove = container.querySelector('span');
if (area.addEventListener) { area.addEventListener('input', function() { span.textContent = area.value; }, false); span.textContent = area.value; }
else if (area.attachEvent) { // IE8 harmony area.attachEvent('onpropertychange', function() { span.innerText = area.value; });
span.innerText = area.value; } // Enable additional CSS container.className += ' active'; } var areas = document.querySelectorAll('.expandingArea');
var l = areas.length; while (l--) { makeExpandingArea(areas[l]); }
A note on delegation: we can simply set this adult with a unaccompanied eventuality listener on a document node
and use eventuality elect to hoop churned expanding ease areas efficiently, yet customarily if you’re not subordinate IE8 or below, as Microsoft, in their enormous wisdom, did not make a onpropertychange
eventuality bubble.
The claim demo
Closing remarks
Due to a proceed redraws are batched in Opera for Mac OS X, a slight nictitate competence start when a new line is total to a ease field. You can work around this by always origination it a line taller than it needs to be in Opera on Mac; customarily addition a following regulation to a tip of a makeExpandingArea
avocation (sadly there’s no proceed to do underline display for this):
if ( window.opera /Mac OS X/.test( navigator.appVersion ) ) { container.querySelector( 'pre' ) .appendChild( document.createElement( 'br' ) ); }
Lastly, given a textarea
is positioned directly over a pre
, we can extend this to do flat things such as syntax highlighting as we type; if we parse a value and apart it into conflicting tags before adding it to a pre
, we can ask conflicting colors to conflicting sections. You’ll need to disturb a visibility: hidden
chapter from a pre
and instead addition color: transparent
to a textarea
. We use this technique in My Opera Mail to make it easier to prove a names in a To/Cc/Bcc fields of a harmonize screen. The barrier is that all browsers other than Opera make a cursor tinge a same as a ease color, so a cursor disappears when we make a tinge transparent. we don’t trust any W3C prevalent covers this (please let me know if I’m wrong), yet a tallness prevalent (based on a ease editors shipped with them) seems to be a opposite of a certification tinge on Windows and always black on Mac, regardless of certification or front color. But until a other browsers see a light and correct this avocation we can still ask a syntax highlighting on foam and spin it off while a user is indeed editing, or change a certification tinge instead.
And that’s it folks! Hope you’ve enjoyed reading this letter and maybe scholastic a useful new technique. It’s glorious and fit and works customarily as good in difficult mobile browsers as on a desktop. Happy hacking! Image may be NSFW.
Clik here to view.