Home > database >  Apply :focus-visible when focusing element programatically
Apply :focus-visible when focusing element programatically

Time:09-22

I want to apply styling to my element when I'm focus it using my keyboard or when focused programatically using HTMLElement.focus().

E.g in the example below. I want the <div> to have blue borders initially or when I focus with tab. I only want it to have red border when I click the <div> using my mouse.

Is this possible?

EDIT1: Changed from triggering focus with a button to just on render as this scenario wasn't accurate to my actual issue.

EDIT2: Changed from vanilla JS to React as I though that might be the issue. Seems like it still works like I want to to here, but not in my App :(. I have no clue why.

const useFocusOnMount = (ref) => {
  React.useEffect(() => {
    if (ref.current) {
      ref.current.focus();
    }
  }, [ref]);
};


const App = (props) => {
  const divRef = React.useRef(null)
  
  useFocusOnMount(divRef);

  return (
  <div ref={divRef} role="listbox" tabindex="0" className="focusable">
    <div data-testid="displayValue">Lol</div>
  </div>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));
.focusable {
  border: 1px solid lightgrey;
  outline: none;
}

.focusable:focus {
  border: 2px solid red;
}
.focusable:focus-visible {
  border: 2px solid blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>

CodePudding user response:

Not sure why you want this, and I would advise you to find an other way to do what you want (e.g, why not use only :focus?).
But for the hack, you can trick the browser in thinking your div is editable, it should* make it trigger its focus-visible rule.

const focusable = document.getElementById('focusable');
const button = document.getElementById('button');

const onClickHandler = (e) => {
  focusable.contentEditable = true;
  focusable.focus();
  focusable.contentEditable = false;
};

button.addEventListener("click", onClickHandler);
.focusable {
  border: 1px solid lightgrey;
  outline: none;
}

.focusable:focus {
  border: 2px solid red;
}
.focusable:focus-visible {
  border: 2px solid blue;
}
<div id="focusable" class="focusable" tabIndex=0>Lol</div>
<button id="button">Focus Lol</button>

*I only tested in latest Chrome and Firefox.

CodePudding user response:

You can't unfocus elements if you point to the element itself.
You must style element with an event listener on body, because outside click is on body, not on the element itself.

You can use e like this to spot where users click.

If e (click) !== (is different to/not on) focs (element) outline = 0.

const focs=document.getElementById('focs');
const focsb=document.getElementById('focsb');

document.body.addEventListener('click',function(e){
  if(e.target!==focs&&e.target!==focsb) {
     focs.style="outline: 0";
  } else if (e.target==focs&&e.target!==focsb) {
     focs.style="outline: 2px solid #000";
  } else {
     focs.style="outline: 2px solid #CC0000";
  };
});
<input id="focs" type="text">
<button id="focsb">Focus</button>

  • Related