focus-visible not properly working on inputs

Hey. We are currently styling an input element and we try to show the outline when the user navigates by keyboard. There is the selector :focus-visible for that. Unfortunately it also gets triggered when we navigate by mouse. I’ve found out, that is a new and intentional behavior for inputs. Buttons and links work just fine. Is there a way to only show the outline when navigating by keyboard and not by mouse? Thanks 😀
11 Replies
MarkBoots
MarkBoots2w ago
you could do a bit of js
<input type="text">
<input type="text">
input.no-focus {
outline: none;
}
input.no-focus {
outline: none;
}
const inputs = document.querySelectorAll("input");
inputs.forEach(input => {
input.addEventListener('pointerdown', focusInput);
input.addEventListener('blur', blurInput)
})
function focusInput(e){
e.target.classList.add("no-focus");
}
function blurInput(e){
e.target.classList.remove("no-focus");
}
const inputs = document.querySelectorAll("input");
inputs.forEach(input => {
input.addEventListener('pointerdown', focusInput);
input.addEventListener('blur', blurInput)
})
function focusInput(e){
e.target.classList.add("no-focus");
}
function blurInput(e){
e.target.classList.remove("no-focus");
}
if the input is clicked (pointer-down) the class no-focus is added, when leaving the input (blur) the class will be removed
xilli
xilli2w ago
Thanks but isn’t it bad for performance, when I’m adding lots of event listeners to lots of inputs?
Jochem
Jochem2w ago
define "lots"
Kevin Powell
Kevin Powell2w ago
I will also say, this is intentional for a reason. It might seem silly, because someone clicked in a box, so they should know where they are, but it's generally considered best practice to still include a focus state on inputs.
xilli
xilli2w ago
I know what you mean and that was my point too. It’s an intentional behavior. But the design team doesn’t want to change the design-system 😦 Well, we are a big insurance company which mostly uses input elements on the website. Maybe around 30-50? The most simple form fields have a minimum of 10 inputs.
Jochem
Jochem2w ago
Testing is king here, but I doubt that'll be a performance issue
xilli
xilli2w ago
I hope so 🙂
Chris Bolson
Chris Bolson2w ago
I agree that that many event listeners shouldn't affect performance. If however it becomes an issue, one alternative would be to use event delegation and apply the event listener to the parent form or container. Starting from Marks code from earlier you could do something like this:
const formEl = document.querySelector("form");
let isKeyboardEvent = true;

formEl.addEventListener("pointerdown", () => {
isKeyboardEvent = false;
});
formEl.addEventListener("touchstart", () => {
isKeyboardEvent = false;
});

formEl.addEventListener("keydown", (e) => {
isKeyboardEvent = true;
handleFocusIn(e);
});
formEl.addEventListener("focusin", (e) => {
handleFocusIn(e);
});
formEl.addEventListener("focusout", (e) => {
handleFocusOut(e);
});

function handleFocusIn(e) {
// only add focus class if is keyboard
if (e.target.tagName === "INPUT" && isKeyboardEvent) {
e.target.classList.add("focus");
}
}
function handleFocusOut(e) {
e.target.classList.remove("focus");
}
const formEl = document.querySelector("form");
let isKeyboardEvent = true;

formEl.addEventListener("pointerdown", () => {
isKeyboardEvent = false;
});
formEl.addEventListener("touchstart", () => {
isKeyboardEvent = false;
});

formEl.addEventListener("keydown", (e) => {
isKeyboardEvent = true;
handleFocusIn(e);
});
formEl.addEventListener("focusin", (e) => {
handleFocusIn(e);
});
formEl.addEventListener("focusout", (e) => {
handleFocusOut(e);
});

function handleFocusIn(e) {
// only add focus class if is keyboard
if (e.target.tagName === "INPUT" && isKeyboardEvent) {
e.target.classList.add("focus");
}
}
function handleFocusOut(e) {
e.target.classList.remove("focus");
}
xilli
xilli2w ago
Thanks. We have to discuss this with our design team. This is not a perfect solution for me to be honest 😦 this will only work with keyboards, not other devices right?
Kevin Powell
Kevin Powell2w ago
I'll give them some credit for realizing they can't just do a :focus { outline: none; } - at least they realize that keyboard navigation requires focus. But yeah, it's so much more work for something that's a bit of an anti-pattern, which sucks.... I mean, as much as the design team doesn't want it, could it be something that's bumped to another level of management? "this could be done in 30 seconds, or we could spend a few meetings and several rounds of testing to make sure there are no edge cases we forgot...." If it's someone who cares about man-hours spent who's listening, you might be able to get the win, lol 😅.
xilli
xilli2w ago
I tried 🙂 If we listen to the TAB key, we might remove accessibility for other input devices. Thanks all for your answers