textarea elements are popular on sites such as Facebook. The height of the
textarea box expands and contracts depending on the quantity of text the user enters. There are several advantages:
- Your page design is not dominated by large
- Online forms with several textareas look shorter and less daunting to complete.
- The user can see all their text without scrolling.
This 3-part tutorial describes how to build an auto-expanding
textarea using HTML and a reusable jQuery plugin. By the end of part 3, you will understand how it works and have code to use in your own projects.
Like all good developers, we should thoroughly understand the system requirements:
textareaon any page should auto-expand when we require it.
- However, some textareas may not require auto-expanding functionality.
- We must be able to specify that a
textareaheight can (a) grow indefinitely, or (b) grow between specific ranges, e.g. use the best height between 50 and 200 pixels.
- Our solution should be re-usable on any page we choose.
- The solution should be cross-browser compatible with IE6+, Firefox 2+, Opera, Safari and Chrome.
We will implement the solution as a jQuery plugin. jQuery is primarily used to handle the more mundane aspects of DOM sniffing and event delegation; you could easily re-write the code using another framework.
But how do we know when a
textarea should be resized and what height do we use?
First, we can assign a “keyup” event handler to any
textarea. This will call a function just after a key has been pressed and the text has been modified.
We can then examine the DOM scrollHeight property. This returns the height of the inner scrolling section, i.e. the height of the text entered by the user. If we set the height of the
textarea to the current scrollHeight value, the scrollbar will become obsolete. Unfortunately, scrollHeight is not a W3C recommendation and there are some cross-browser inconsistencies we need to overcome:
- In Firefox, Safari and Chrome, the scrollHeight is never smaller than the textarea height — even if no text has been added. Therefore, the box would expand but deleting text would not shrink it. We can fix this issue by temporarily setting the textarea height to 0px then applying the real scrollHeight value.
- Contrary to the Mozilla scrollHeight documentation, Firefox does not appear to include textarea padding whereas Safari 4 and Chrome 2 do. If we have 2px padding at the top and bottom, scrollHeight will be 4px too large in the WebKit browsers and the textarea height would grow indefinitely. Subtracting the padding would break Firefox, so the easiest fix is to apply 0px vertical padding to our expanding textarea elements.
- In IE and Opera, scrollHeight is quirky. It normally returns the true height of the inner text, however, setting the textarea height to 0px can return incorrect scrollHeight values. Although browser sniffing stinks, I don’t think we have an alternative in this situation. We must ensure IE and Opera never set a textarea height of 0px.
We also need to consider the scrollbar. By default, most browsers only show the
textarea scrollbar when it’s required. However, if we leave overflow set to “auto”, the scrollbar would appear as a new line is added then disappear as the
textarea height is changed. Setting the overflow to “hidden” will solve flickering scrollbar issues, but that must never be applied to non-expanding textareas or those that have expanded beyond their specified maximum height.
Finally, browser window resizing could be an issue. Fluid web designs could implement a
textarea with a percentage-based width: resizing the window would resize the box. Although we can detect window resizing, the event behaves badly in IE and rapidly calls the handler. We can can code around this problem but resizing several textareas could cause the page design to jump around and confuse the user. Therefore, following a resize, we will only adjust the height of a
textarea once the user has switched focus to that box.
That’s a lot to take in and there’s more to come! Make yourself a coffee and get ready for part 2…