Why :focus-within is huge

Writing a post on any CSS selector or property (or even any new one coming up) would produce a long (and boring) blog. But :focus-within is different – and it’s something I have been waiting for forever. To me, it’s more than another pseudo-class, it’s a game-changer in many ways. And it’s in the stable versions of both Chrome and Firefox (and others). See the MDN page on :focus-within for a full (and esp. up2date) info on browser support.

What :focus-within does is quite simple, actually: it allows styling the parent(s) of the element that has the focus. Opposed to :focus (which references the element having the focus itself), it can be the direct parent, or the parent’s parent or the parent of the parent’s parent or… (you get it).

There is a plethora of use cases – esp. those with extensive handling of onfocus and onblur events.

My example

Here is something quite common to demonstrate: while the focus is with an input, a small hint shall be displayed (and disappear after tabbing out / clicking somewhere else). Here’s how it can look like (when you live in Hamburg, you might even know the answer):

‘Traditional’ way of doing it

Per se (and this works like forever), you’d have to react to the onfocus and onblur events of the input itself in order to set style classes:

<span class="tooltipWrapper">
  <input size="4" onfocus="focusInput(event)" onblur="blurInput(event)"/>
  <div class="tooltip">
    <div class="tooltipContent">Think long & hard</div>
  </div>
</span>

along with

function focusInput(evnt) {
  evnt.target.parentNode.classList.add("focused");
}
function blurInput(evnt) {
  evnt.target.parentNode.classList.remove("focused");
}

and some (S)CSS to position the tooltip (using position-relative):

// core
.tooltipWrapper {
  position: relative;
  .tooltip {
    display: none;
    position: absolute;
    left: -50%;
    top: 100%;
    width: 200%;
  }
  &.focused {
    .tooltip {
      display: block;
    }
  }
}
// making it nice
// ...
// housekeeping
// ...

Nothing about it is hard or surprising, it just becomes a lot of work, especially when nesting components or styles. With a little discipline, it is manageable. Yet overall, it

  • clutters the code
  • results in unnecessary work
  • is prone to error
  • gets unmanageable over time

The main point is that the focused class needs to be set to the input’s parent (the :focus selector would not cut it). Again: nothing is particularly hard – it’s just daunting work.

By the way, changing &.focused to &.focused, &:hover also displays the tooltip on hovering the input (actually: the input’s wrapper).

There is a better way

And what’s even better: it’s all about changing one line: going from &.focused to &:focus-within. That’s it. That’s all, really. The JavaScript can go away completely, all it needs is

<span class="tooltipWrapper">
  <input size="4"/>
  <div class="tooltip">
    <div class="tooltipContent">Think long & hard</div>
  </div>
</span>

along with (S)CSS:

// core
.tooltipWrapper {
  position: relative;
  .tooltip {
    display: none;
    position: absolute;
    left: -50%;
    top: 100%;
    width: 200%;
  }
  &:focus-within /* !!!!! */ {
    .tooltip {
      display: block;
    }
  }
}
// making it nice
// ...
// housekeeping
// ...

Both code sniplets achieve the exact same result (incl. poss. extension w/ , &:hover), just that the latter is

  • clear and concise
  • free of daunting work
  • stable (no matter how components and styles are nested)
  • pretty manageable (and just pretty)

As :focus-within works on direct and indirect parents (parent’s parent, and so on), I can go and do even more styling. For instance, label:focus-within { background: lightgrey; } highlights the label having the focus.

So?

Using :foucs-within makes highlighting and tooltips much easier and much more manageable. It adds a really powerful tool to create Web UIs with (only) CSS, making them very intuitive and usable.

I’ve put up three codepens to demonstrate:

As ever, feel free to try it for yourself – and let me know what you think!

Posted in All

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s