Styled input controls in html

Well its been a very long time since I posted anything on this blog, to be quite honest I’ve simply been very busy both personally and professionally.

As always I’ve got *heaps* of projects on the go, so I’ll try and write ‘em up and link to some of the source soon, or better-still, actually finish some of them and host the working end product!

In the mean-time one of my personal projects is a little javascript app using the popular Angular-js framework. I wanted some input controls with the ability to put coloured underlines under user-entered text.

editable text with wavy underlining that can be applied by javascript

<input type=”text”> may be easy to use, but it’s pretty much impossible to style it. What I really wanted was some kind of magical input control where I could actually style the text in the input. But before I could apply the wavy underline style to the input control I needed to figure how to style a wavy underline with regular markup.

Most coders will be familiar with jsfiddle and its ilk – basically websites which allow you to enter code directly in the browser with all the syntax-colouring goodness we’ve come to expect from professional IDEs. The fact this is even possible at all in a browser window is pretty damn cool if you ask me.

Anyway, the back-end behind all this goodness is usually a javascript library called CodeMirror. It uses a hidden input control to accept the input then runs some background tasks which perform the syntax highlighting and so on. It’s open-source and the code is sweet. If you get a chance, I thoroughly recommend checking it out on github.

For my needs however, full-blown syntax highlighting wasn’t a requirement, I was wanting to explore the ability to highlight up specific words if they occurred in the text the user entered. Initially I wanted to do something like underline text with that ubiquitous wavy line to match the look and feel we’re all familiar with in applications like Microsoft Word when something is misspelled. CSS3 tantalisingly brings this possibility up with some new style properties, text-decoration-color and text-decoration-style:

text-decoration: underline;
text-decoration-color: magenta;
text-decoration-style: wavy;

Sadly, these styles just aren’t supported in enough browsers yet. In fact, I can only get the wavy style working in Firefox with a vendor extension -moz-text-decoration-style: wavy; So unless you’re using a modern version of Firefox I expect you’re not seeing much in the way of wavy styling.

A fallback solution with complete cross-browser support is to use an image border on a <span> with a wavy image.

Here’s an example of a wavy underline achieved in this way:

cross-browser underline with a different colour to the text being underlined

(NB. it falls back to a double border for those of you whose browsers don’t support border images – come on now upgrade your browsers people!).

and here’s the corresponding css:

.magenta-underline {
    border: 3px double magenta; 
    border-width: 0px 0px 3px 0px; 
    -moz-border-image: url(images/wavyunderline.png) 0 0 3 repeat; /* Firefox */
    -webkit-border-image: url(images/wavyunderline.png) 0 0 3 repeat; /* Safari 5 */
    -o-border-image: url(images/wavyunderline.png) 0 0 3 repeat; /* Opera */
    border-image: url(images/wavyunderline.png) 0 0 3 repeat;
}

If you don’t want to go the whole hog with wavy underlines a simple straight line border is even easier to accomplish of course. Note that the easiest way to create cross-browser compatible css for border-images is with a generator such as border-image.com. This faked underline is a little lower than an ordinary underline, but personally I can live with that. You could probably muck around with border-image outsets or padding or margins or something to get it closer, but sometimes life is too short for absolute perfection!

This is all very nice I hear you cry, but it still doesn’t address the ability to underline content in a user input control does it? That is after all the crux of why I’m making this post in the first place…

One could attempt to emulate CodeMirror for this functionality, with a hidden input control and normal markup for the actual text. However, that’s a heavyweight solution with a lot of js code for something that shouldn’t be so complex. All I really wanted to accomplish was on-the-fly underlining of user input. A quick google and I found out about a nice feature I’d somehow managed to be oblivious to for years: contenteditable=”true”.

This innocuous little piece of markup transforms any ordinary div or block element into an editable text field! Sweet. Here is some markup

<div contenteditable="true">
editable <span style="color:red">styled text</span> here!
</div>

and the result… go ahead and try editing it!

editable styled text here!

Now with a bit of behind the scenes javascript we can highlight words when the user clicks “update”… try typing in the input below and if you type the word “dog” you should see some wavy underlining magic going on when you click :

type in here… when you click [update underlines] every occurrence of dog will have a wavy underline

Of course, ideally you want the wavy underlines automatically applied while you’re typing. The basic gist is to either poll with setTimeout() or attach an oninput handler. The problem lies in the caret position being moved when you replace the contents with the new contents with the wavy underline styles applied. In order to make that work, you need to store the caret position prior to applying the styles, then relocate the caret (to its new position) after applying the styles. Realistically you need to use a library like Rangy for that, because there are no trivial cross-browser solutions, but I’ll leave that explanation for another day!