Highlight Text Inside a Textarea

Let’s start with the bad news. You can’t actually highlight text in a <textarea>. Any markup you would add to do so would simply display as plain text within the <textarea>. The good news is, with some carefully crafted CSS and JavaScript, you can fake it.

This article will show you how to pull it off, but if you just want the solution, feel free to go straight to the jQuery plugin: highlight-within-textarea.

Highlight within textarea


Way back in 2010, I made a site called Regex Storm that would highlight regex matches in a <textarea>, like this. It’s not hard to imagine other applications for this sort of “find and highlight” functionality. 5 years is a long time though, so I decided to revisit the concept and fix it up for modern browsers.

The Plan

The basic idea is to carefully position a <div> behind the <textarea>. JavaScript will be used to copy any text entered into the <textarea> to the <div>. A bit more JavaScript will make that both elements scroll as one. With everything perfectly aligned, we can add markup inside the <div> to highlight text, which will show through the <textarea>, completing the illusion.

A demo should make this all clear. Scroll around and edit the text. Then click Toggle Perspective and edit and scroll some more.

See the Pen Highlight Text Inside a Textarea by Will Boyd (@lonekorean) on CodePen.


It takes a couple of elements to achieve the layout we need.

The container <div> simply serves as an anchor to position other elements within. The highlights <div> is nested within the backdrop <div>, which may seem like 1 more <div> than we need, but doing it this way fixes some subtle scrolling bugs (which we’ll get to later).

The <mark> tag is the best semantic choice for highlighting text inside the highlights <div>. We’ll be inserting these tags with JavaScript.


Elements must be laid out with pixel perfection. This can be tricky, as many browsers have very subtle differences that normally aren’t worth caring about, but are very noticeable in this case.

For example, Firefox adds a single pixel of margin to the top and bottom of a <textarea>. And iOS adds a border-radius to <textarea>. So we have to fix these styles (and others I haven’t specifically mentioned).

CSS is used to make text inside the highlights <div> wrap and scroll exactly like the text inside the <textarea>.

It’s also important to set the visibility of things so that our stacked elements display properly together. Remember, the <textarea> sits on top of the highlights <div>.


The JavaScript has 3 main responsibilities.

  1. Keep text in the highlights <div> synced with text in the <textarea>.
  2. Highlight text in the highlights <div> with <mark>.
  3. Make the highlights <div> scroll in tandem with the <textarea>.

Let’s start by binding 2 events.

The input event triggers whenever text in the <textarea> is changed. The callback function takes this text, applies highlights to it, then inserts it into the highlights <div>.

And here’s the applyHighlights() function.

applyHighlights() actually does 2 things. On line 3, it fixes a bug where a trailing carriage return causes the highlights <div> to become misaligned. Then on line 4, it does the actual highlighting by inserting <mark> tags. The regex in this example highlights all capitalized words, but this can be customized.

The scroll callback copies the scroll position of the <textarea> to the backdrop <div>, so that they both scroll in tandem.

Wrap Up

That covers the basic mechanics of (fake) highlighting within a <textarea>. Please note that there are some finer details that this article didn’t discuss and the demo didn’t account for. For the more comprehensive, more bullet-proof solution, check out the highlight-within-textarea jQuery plugin on GitHub.

Checkbox Trickery with CSS

Checkboxes are great. Combine them with the right CSS and you can pull off some really neat tricks. This article aims to showcase some of the creative things you can do with checkboxes. Read on and keep in mind that the demos in this article use no JavaScript.

The Basic Formula

It all starts with the HTML.

Nothing tricky there. The for attribute on <label> matches the id on <input>, so clicking on the <label> will toggle the <input> checkbox. This is important, because our next step is to hide <input>.

Why not display: none? Because that would cause it to be ignored by screen readers and keyboard tabbing. This method keeps <input> in the flow, but hides it offscreen.

Hiding <input> makes it easier for us to do our own thing. We still need to convey the checked/unchecked state, but we can do that with <label>. This is where the party starts.

We’re using a combination of the :checked pseudo-class and the + adjacent sibling selector to say “when the checkbox is checked, find the <label> right after it and apply awesome styles”. You can even use pseudo-elements (::before and ::after) within <label> for more creative freedom.

Alright, let’s see it in action. This demo uses the basic formula we just discussed to turn regular checkboxes into something more impressive.

See the Pen Checkbox Trickery: Simple Toggle by Will Boyd (@lonekorean) on CodePen.

The best part is, they’re still checkboxes. Wrap them in a <form> and they’ll submit just like you’d expect. We’re changing appearances, but not behavior.

Hiding/Showing Content

So far it’s been all about styling <label>, but we can go beyond that. This demo dynamically hides/shows parts of a form based on user selection.

See the Pen Checkbox Trickery: Form Disclosure by Will Boyd (@lonekorean) on CodePen.

The :checked pseudo-class works on radio buttons the same as checkboxes. With that in mind, here’s the HTML for the “How did you hear about us?” radio buttons.

The radio button indicators are rendered within <label> using a combination of ::before (for the outer ring) and ::after (for the green dot). Showing/hiding ::after when a radio button is checked/unchecked is easy enough.

The <div> is hidden until the radio button for “Other…” is checked. I hide the <div> with display: none, because this time I do want the content to be ignored by screen readers and keyboard tabbing until revealed. The CSS to reveal the <div> when the radio button is checked looks like this.

We’ve been using the + adjacent sibling selector up until now, but this time we’re using the ~ general sibling selector. It’s similar, but can find non-adjacent siblings, like our <div>.

Folder Tree

We can reuse the techniques from the previous demo to create a folder tree widget, which has similar hide/show behavior.

See the Pen Checkbox Trickery: Folder Tree by Will Boyd (@lonekorean) on CodePen.

The HTML for a single folder is given below. The <label> is the folder and the two <a> elements are “files” within it.

Font Awesome icons are used to indicate checked (open) and unchecked (closed) states.

Content within a folder is toggled with a ~ general sibling selector. This is why there are extra <div> wrappers in the HTML, to keep this selector from “leaking out” and opening sibling folders.

Naturally, folders can be nested. Just drop the HTML for another folder into <div class="sub">. Click the “Multicolor” folder in the demo to see an example.

Lastly, let’s talk about that reset button.

Form reset buttons are rarely used anymore, but this is a decent case for one. Clicking it returns all checkboxes to their initial unchecked state, closing all folders. Neat.

Split List

This demo splits items into two separate lists depending on whether they’re checked done or not.

See the Pen Checkbox Trickery: To-Do List by Will Boyd (@lonekorean) on CodePen.

Update: Some people have pointed out that the convention is for checkboxes to be square, unlike what I’ve done in this demo. They’re not wrong.

The HTML looks like this.

The split list mechanic is achieved with CSS flexbox. Here’s the relevant CSS.

CSS flexbox lets you directly rearrange elements with the order property. The order value of a <label> is changed from 4 to 2 when its checkbox is checked, moving it from below the “Not Done” <h2> to below the “Done” <h2>.

Unfortunately, keyboard navigation and many screen readers will follow the order of elements in the DOM, even if they’ve been visually reordered using CSS flexbox. This makes the “Done” and “Not Done” headers useless to screen readers, which is why I added aria-hidden="true" to them — better they be ignored than cause confusion. Besides that, the split list is still fully operable via keyboard and screen readers will still announce the state of an item (checked/unchecked).

If you’re curious about the counts next to “Done” and “Not Done”, those are generated with CSS counters. Check out this article if you want to learn more.

Group Filtering

Last demo. This one shows how to highlight a cross section of data that matches a selected criterion.

See the Pen Checkbox Trickery: Group Filter by Will Boyd (@lonekorean) on CodePen.

Here’s the abbreviated HTML. Notice how the data-teams attribute is a space-separated list of radio button id attributes. This is how we map characters to teams.

Regarding accessibility, I use empty alt attributes because the character names are already in the <h2> tags — no point having each name read twice. Also, since I’m not actually hiding <img> elements (just shrinking and fading), this makes it easier to get screen readers to skip unhighlighted characters. I only need to hide the <h2>.

Here’s the CSS that highlights characters when their team is selected.

I know these selectors look hairy, but they’re not so bad. Let’s dissect line 1 as an example. Talking it out, “when the element with an id of ‘original’ is checked, look within the sibling ‘characters’ element for anything with a data-teams attribute containing ‘original’, then find the <h2> within. Repeat for ‘force’, ‘factor’, and ‘hellfire’ on lines 2-4. Now do it all again on lines 8-11, but for <img> instead of <h2>.

Parting Words

I hope you had as much fun playing with these demos as I had making them. It was very interesting to me, seeing what I could pull off with something as modest as a checkbox. I have no qualms using JavaScript when appropriate, but it’s nice being able to accomplish so much without it. Thanks for reading!

Update: The kind folks at Webucator put together a video tutorial for this article.

51 comments » Related topics:

Iconifying Content

This tutorial will walk you through the concept of iconification — taking content on a page and applying CSS to transform it into a simplified, icon-sized preview of itself.

Let’s dig into an example. This demo shows iconifying applied to calendars. Click on the month icons to expand them.

Iconifying content: calendar

Visual Abstraction

In the calendar example, the icon view uses simple colored squares to indicate that a month contains dates of interest. Each icon can be clicked to trigger the full view with more details, such as date numbers and names of holidays. The smooth transition between the two maintains context, so the relationship is very intuitive.

This is where iconification really shines. It’s great for presenting a compact overview of content while still having the details available in an instant. In other words, it allows for visual abstraction of information.


Here’s the HTML for a single month.

No surprises there. Calendars are really just days organized in a tabular format, so <table> is the obvious semantic choice. Each month is wrapped in an <article> to convey that it’s a self-contained piece of content. Every <article> has tabindex="0" on it to enable tabbing, which is important for keyboard accessibility (more on this later).


There’s a lot of CSS, so I’ll just cover the highlights. The full CSS is available in the source and includes comments for a couple of browser-specific fixes.

Each <article> is centered within an <li>, which is positioned within a <ul>. The centering technique I use on <article> allows it to overlap surrounding content and stay centered when expanded to full-size. Relevant declarations are shown below.

Notice the transform property also has scale(.25) on it. This isn’t for centering, rather it’s what creates the 1/4th icon sizing.

Restoring <article> to full-size is done by adding the active class to its parent, causing the transform property on <article> to change.

scale(1) is self-explanatory, but it’s worth noting that translate(-50%, -50%) needs to be restated, otherwise <article> will shift back to its non-centered position.

At the same time, the inactive class is added to sibling elements so that another <article> cannot be expanded until the active <article> is dismissed. This is done by blocking pointer events.

z-index stacking requires some finesse. The active <article> needs to appear above neighboring content. This means increasing the z-index when the expanding animation starts (easy part) and not resetting the z-index until the shrinking animation ends (tricky part). Fortunately, z-index is animatable, so we can use transition-delay to make this happen.

The active class also triggers opacity changes on various child elements, giving us that nice fade in/out effect on the details.

Of course, none of this would be animated without the transition declarations on <article> (for scaling) and the various child elements (for fading).

Pixel Perfection

Achieving pixel perfection with transformed elements — before, during, and after animation — takes patience. There are many quirks to battle, but fortunately, there are a few tricks and best practices that help.

All pixel sizes in the CSS are multiples of 4. This is no coincidence. The content is scaled to 1/4th size when displayed as an icon, so using multiples of 4 ensures that fractional pixel sizes don’t happen. This keeps pixels perfectly aligned and edges crisp.

Defining the widths and heights of elements can help. Not only does this make it easier to achieve the pixel alignment just discussed, but it can also prevent post-animation jiggles. Browsers will often readjust text when an animation ends. If an element containing such text doesn’t have a set width/height, then it’ll resize accordingly, causing a chain reaction of positional shifting to elements after it.


Iconifying content naturally involves a lot of elements in a small space. With so many elements to animate, it’s important to keep performance in mind, otherwise you’ll end up with a poor framerate and ragged transitions.

There are two things you should avoid: repaints and reflows. Repaints are caused by animating properties that force your browser to redraw elements. This includes color, background, box-shadow, and more. Reflows are caused by animating properties that force your browser to update the layout of elements. This includes width, height, margin, top, left, and more.

Repaints and reflows aren’t the end of the world, but they can hurt performance. You can avoid these by sticking with two properties that are very efficient to animate because they get help from the GPU: opacity and transform (when used for position, rotation, or scale).

This explains some of the decisions made in the CSS. There are places where animating color or background-color would be more intuitive, but opting for an approach that uses opacity allows for better performance.

JavaScript and Accessibility

JavaScript is used to handle the behavior of expanding and shrinking content. Mouse clicks are the obvious trigger, but keyboard accessibility is also important, so the JavaScript covers that as well. jQuery is used for convenience.

Clicking/tapping an <article> calls activate(), which applies the active class to the appropriate element and the inactive class to the others.

Clicking the dismiss icon or tabbing/clicking away from an <article> calls dismiss(), which simply removes the active and inactive classes.

checkKey() brings support for certain key presses. Hitting enter will toggle the current <article>. Hitting escape will dismiss the current <article>, if it’s expanded.

That wraps up my first example. You can check out the finished demo, in case you missed it earlier.

Second Demo

Next up is a concept for iconifying profile cards. Go ahead and check out the demo.

Iconifying content: profiles

A lot of techniques from the first demo are reused here. The new point of interest is in turning the individual words in the profile text into abstract blocks. The first step to accomplishing this is to wrap each word in its own <span> tag so that we have something to work with. This would be really tedious by hand, so let’s have JavaScript do the work for us.

That snippet simply grabs text within <p> tags, breaks it apart wherever it sees a space, then wraps each piece with <span> tags. Now we can use those <span> tags to apply some CSS.

The actual <span> tag is mostly left alone. Instead, an ::after pseudo-element is used to cover each word with a block of color. The top and bottom properties are given slightly negative values in order to stretch the block to cover letters that stand tall or hang low (“g”, for example).

Sadly, this makes the blocks a bit thick, which isn’t as visually appealing. The solution is to use a carefully crafted linear gradient that pads the top and bottom with white (to match the background). The blocks appear thinner, the text is still covered, everyone is happy.

Be careful though, this “spanifying” technique should be used in moderation. It’s very easy to get carried away and blow up your DOM tree with way too many <span> elements, each one being animated, which can lead to performance issues. It’s best to stick with small blurbs of text, like in the example.

Third Demo

My final demo shows iconification in the context of an analytics dashboard.

Iconifying content: dashboard

This demo has a lot going on, but doesn’t really introduce any new techniques for iconifying content, so I’ll leave it at that. If you want to see all the glorious details, the source is all yours.


I can see iconification being used in many other situations beyond the 3 I’ve shared here. It’s a great tool to help with visual abstraction and information hierarchy. There’s also a sort of slick elegance in being able to show a true icon-sized preview of real content by applying a coat of CSS to the content itself. Just be mindful to keep your pixels sharp and don’t forget about performance.

Crazy Meta CSS Hack

There are several HTML tags that aren’t rendered on a page. Tags like <head>, <meta>, <script> — all very important, but browsers don’t display them. The interesting thing is, browsers can display them, they’re just told not to by the user agent stylesheet:

User agent hiding elements

So what happens when you override the CSS that hides them? Crazy meta CSS hacks happen.

Show Me Your CSS

Here’s a fun trick. You can enable the display of <style> blocks, essentially creating CSS that shows itself (without JavaScript):

See the Pen Display CSS with CSS by Will Boyd (@lonekorean) on CodePen.

The CSS has some extra fluff for presentation’s sake, but the heart of it is very simple:

What’s It Good For?

That’s neat and all, but is it useful? Nope! Thanks for reading!

Actually, it could be useful as a development tool. Imagine a specially crafted stylesheet that visualizes hidden markup on a page — meta tags, stylesheets, script references, etc. Developers could quickly see what’s behind the curtain without having to poke around in dev tools or search the source code.

Here’s a prototype (again, no JavaScript):

See the Pen Visualizing Hidden Tags by Will Boyd (@lonekorean) on CodePen.

There’s quite a bit of CSS shenaniganery going on there. I won’t bore you with the line-by-line, but here are the highlights.

I only show tags when they have certain attributes on them. The <meta> tag in particular has several possible attributes, but I only care for some of them. So I use attribute selectors to pick them out. For example, to only show <meta> tags that have name and content:

The big difference between this demo and the earlier one is that I’m displaying the attributes of these elements instead of their inner text. Very different. Fortunately attr() makes it possible to pull text out of an attribute and display it via a pseudo-element:

In case you didn’t notice, the tag counts are also being displayed — <meta> #1, <meta> #2, etc. This is done with CSS counters:

Closing Remarks

Like any hack, you should use your best judgement before applying it. I really don’t see this being used in production. For development, maybe. For crazy-go-nuts experimental demos, absolutely!

3 comments » Related topics: