5
votes

I want to perform a function after a div element has left focus.

I'm using tabIndex and onBlur function inside the div. And its working fine when i manually put focus by clicking on any of the elements inside the div. But by default when no item is clicked inside the div, its not working.

My component is a Functional Component & the div is rendered dynamically so also I'm unable to set focus using useRef.

const renderHeaderCell = (header, headerKey) => {
    return (
      <div className="DataTable__header-cell-wrapper">
        {filterable ? (
          <IconButton onClick={() => toggleFilterPanel(headerKey)}>
            <i className="material-icons">filter_list</i>
          </IconButton>
        ) : null}
        {activeFilterHeader === headerKey ? (
          <div
            tabIndex={0}
            onFocus={e => {
              console.log("DIV", "focus");
            }}
            onBlur={e => {
              console.log("DIV", "blur");
            }}
            style={{ border: "1px solid blue" }}
          >
            DIV container
            <input
              type="text"
              onFocus={e => {
                console.log("input", "focus");
              }}
              onBlur={e => {
                e.stopPropagation();
                console.log("input", "blur");
              }}
              placeholder="Inside Textbox"
            />
            Click outside
          </div>
        ) : null}
        {sortedByColumn === headerKey ? renderSortIcon() : null}
      </div>
    );
  };

Code after i click the icon to show the DIV

  const toggleFilterPanel = headerKey => {
    if (activeFilterHeader === headerKey) {
      setActiveFilterHeader("");
    } else {
      setActiveFilterHeader(headerKey);
      setUniqueItemsForFilter(getUniqueItemsForFilter(rows, headerKey));
    }
  };

Code after onBlur is called

const onBlur = () => {
    console.log("Blured");
  };

So how shall i make onBlur to work on a div element?

Following image shows current focus

enter image description here

1
I suggest you use onBlur and onFocus only on focusable elements. The reason is that safari ignoring tabIndex by default. So you can't relay on that behaviour if you want cross browser supportArseniy-II
Sorry, I don't get where is the focus when you say "it's not working"keul
It means that on safari <div tabIndex={0} onBlur={onBlur}> will not be focusable. onBlur and onFocus on such elements will not work on safari too.Arseniy-II
@Arseniy-II not sure this is true (alhtough the general suggestion is valid). I think that Safari ignore tabindex for having a tab order, but it's not ignoring tabindex="0" for enabling focuskeul
@keul I recap my knowledge about that issue. You are right safari doesn't ignore tabindex="0". <div tabIndex={1}> will be focusable and onBlur and onFocus will work. But there is another problem <button> is not focusable element on safari. And <button tabindex="0"> will be not focusable too.Arseniy-II

1 Answers

6
votes

blur event may be very trick especially if you have focusable elements inside focusable element. Open console and play with that piece of code a little bit in order to understand better how 'blur' and 'focus' events work.

class BlurExample extends React.Component {
  render() {
    const {title} = this.props;
    return (
      <div
        tabIndex={ 0 }
        onFocus={ () => {console.log('main', 'focus');} }
        onBlur={ () => {console.log('main', 'blur');} }
        style={ { border: '1px solid coral', padding: '10px', fontFamily: 'sans-serif' } }
      >
        Click here 1
        <input
          type="text"
          onFocus={ () => {console.log('input', 'focus');} }
          onBlur={ () => {console.log('input', 'blur');} }
          placeholder="Click here 2"
          style={ { margin: '0 10px', padding: '10px' } }
        />
        Click here 3
      </div>
    );
  }
}
  
ReactDOM.render(
  <BlurExample />,
  document.body
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

blur event won't happen if you click inside focused element. Exception if you have another focusable element inside and you click on it. But Notice that after main blur you will see input focus and main focus and if you will click outside of the main element you will also see two blur events: input blur and after that main blur