miir
miir

Reputation: 1926

:focus-within styles flash when clicking an input label

Problem:

Clicking on an input label within a parent element with :focus-within styles causes an undesirable flash of the :focus-within styles.


Background:

I wanted to use :focus-within to improve accessibility by providing the user with some visual feedback when a group of related radio-buttons is in focus.

Attaching labels to the radio buttons allows the user to click a label to select the corresponding radio button. However, clicking the label causes the :focus-within styles to flash off while the mouse is down.

HTML

<div class="parent">
    <label><input type="radio" name="x"/>First</label>
    <label><input type="radio" name="x"/>Second</label>
    <label><input type="radio" name="x"/>Third</label>
</div>

CSS

.parent {
    border: 2px solid grey;
    padding: 10px;

    &:focus-within {
        background: skyblue;
    }
}

https://jsfiddle.net/ggamir/nb3sy26k/

Upvotes: 3

Views: 1778

Answers (1)

miir
miir

Reputation: 1926

Solution

Add tabindex="-1" to the labels. This allows them to become "focusable" elements without being part of the tabindex order.

https://jsfiddle.net/ggamir/krnavadz/


Explanation

When a user begins clicking on a label (mousedown), the previously focused radio button loses its :focus state.

When the user completes the click (mouseup) on a label, the browser selects the corresponding radio button and gives it a:focus state.

By default, the label element is "unfocusable", so while the mouse is down on the label, nothing in the parent has focus, which is why the :focus-within styles are removed for that moment.

Adding tabindex to the label makes it a "focusable" element, so while the mouse clicks down on it, the parent still has :focus-within, so the styles will remain applied throughout the whole duration of the click.

Using -1 in tabindex="-1" is important so that the label doesn't unnecessarily get added into the tabindex order.

Note

There are some default :focus and :active styles for elements which will be applied to the label once it is made "focusable" through tabindex, so clearing those may be desired so as to not confuse the user:

.my-label:focus, .my-label:active {
    outline: none;
}

Upvotes: 3

Related Questions