Accessible, keyboard-friendly way to remove focus style from checkbox label after mouseup

Viewed 1917

I have styled input:focus + label to visually indicate when an input has been focused using keyboard navigation.

But Chrome (and maybe not just Chrome?) persists the :focus state after using a mouse to click the input, which looks ugly.

I want to remove the :focus styling after the click without altering keyboard navigation. i.e., when you move your mouse away after clicking a label, it should no longer be red.

I have seen suggestions to .blur() the input on mouseup; but 1) it hasn't worked for me (see snippet below), and 2) I'm concerned it will take keyboard navigation out of its usual flow.

Yes, someone using the mouse to click a checkbox and then going to keyboard navigation is an edge case. But it's one I would like to account for.

$("label").mouseup(function () {
 $(this).blur();  // This has no apparent affect.
 $("#" + this.htmlFor).blur();  // Or this.
});
input:hover + label, input:focus + label {
  color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
  <p>Form Part One</p>
  <input type="checkbox" id="cb1" name="cb" /><label for="cb1">First Checkbox</label><br>
  <input type="checkbox" id="cb2" name="cb" /><label for="cb2">Second Checkbox</label>
  
  <p>Form Part Two</p>
  <input type="radio" id="r1" name="r" /><label for="r1">First Radio</label><br>
  <input type="radio" id="r2" name="r" /><label for="r2">Second Radio</label>
</form>

3 Answers

EDITED based on comment:

//set checkbox hover
$("input").hover(function() {
  $(this).next("label").css("color", "red");
}, function() {
  $(this).next("label").css("color", "black");
});
//set label hover
$("label").hover(function() {
  $(this).css("color", "red");
}, function() {
  $(this).css("color", "black");
});
//set checkbox focusin focusout
$("input").focusin(function() {
  $(this).next("label").css("color", "red");
  $(this).next("label").siblings().css("color", "black");
});
//set checkbox label active on click
$('input:checkbox').on('click', function() {
  $(this).next('label').toggleClass('active');
});
//set radio label active on click
$('input:radio').on('click', function() {
  $(this).next('label').toggleClass('active');
  $(this).siblings().next('label').removeClass('active');
});
.active {
  color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
  <p>Form Part One</p>
  <input type="checkbox" id="cb1" name="cb" /><label for="cb1">First Checkbox</label><br>
  <input type="checkbox" id="cb2" name="cb" /><label for="cb2">Second Checkbox</label>
  <p>Form Part Two</p>
  <input type="radio" id="r1" name="r" /><label for="r1">First Radio</label><br>
  <input type="radio" id="r2" name="r" /><label for="r2">Second Radio</label>
</form>

I might be misunderstanding you here, but I think the issue is that you are putting your event trigger on the wrong element. Input is the parent of label in the case of your html structure, and is the active element upon which the mouseup event should trigger.

  

$("input").mouseup(function () {
 $(this).blur();  // This has no apparent affect.
 $("#" + this.htmlFor).blur();  // Or this.
});
input:hover + label, input:focus + label {
  color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
  <p>Form Part One</p>
  <input type="checkbox" id="cb1" name="cb" /><label for="cb1">First Checkbox</label><br>
  <input type="checkbox" id="cb2" name="cb" /><label for="cb2">Second Checkbox</label>
  
  <p>Form Part Two</p>
  <input type="radio" id="r1" name="r" /><label for="r1">First Radio</label><br>
  <input type="radio" id="r2" name="r" /><label for="r2">Second Radio</label>
</form>

When you click on a label for a checkbox, the focus is transferred to the checkbox. However, the focus will not have been transferred by the time the mouseup event listener fires. So you were clearing the focus on the wrong element, and even if you had tried to clear the focus for the correct element, that element would not yet have focus.

You can achieve the effect you're looking for by adding a momentary focus event listener on the checkboxes to immediately clear the focus inside your mouseup listener. This will only fire once the checkbox receives focus, and will only fire if there is a mouseup event, so it will not interfere with the keyboard users.

$("label").mouseup(function () {
    $(this.previousElementSibling).one('focus', function() {
        $(this).blur();  // This has an apparent affect.
    });
});
input:hover + label, input:focus + label {
  color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
  <p>Form Part One</p>
  <input type="checkbox" id="cb1" name="cb" /><label for="cb1">First Checkbox</label><br>
  <input type="checkbox" id="cb2" name="cb" /><label for="cb2">Second Checkbox</label>
  
  <p>Form Part Two</p>
  <input type="radio" id="r1" name="r" /><label for="r1">First Radio</label><br>
  <input type="radio" id="r2" name="r" /><label for="r2">Second Radio</label>
</form>

Related