9

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

Neel Dsouza
  • 1,342
  • 4
  • 15
  • 33
  • 1
    I suggest you use `onBlur` and `onFocus` only on focusable elements. The reason is that [safari ignoring tabIndex by default](https://stackoverflow.com/questions/1848390/safari-ignoring-tabindex/1914496). So you can't relay on that behaviour if you want cross browser support – Arseniy-II Aug 26 '19 at 14:09
  • Sorry, I don't get where is the focus when you say "it's not working" – keul Aug 26 '19 at 14:09
  • 1
    It means that on safari `
    ` will not be focusable. `onBlur` and `onFocus` on such elements will not work on safari too.
    – Arseniy-II Aug 26 '19 at 14:11
  • @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 focus – keul Aug 26 '19 at 14:12
  • @keul The focus is on the button which i click, to open the div which i want to make focusable. I've added a screenshot to show where my focus is currently. – Neel Dsouza Aug 27 '19 at 05:32
  • 1
    @keul I recap my knowledge about that issue. You are right safari doesn't ignore `tabindex="0"`. `
    ` will be focusable and `onBlur` and `onFocus` will work. But there is another problem `
    – Arseniy-II Aug 27 '19 at 06:00
  • @NeelDsouza, please provide more code it is unclear what maybe wrong with your code. Ideally you should provide enough code to reproduce the bug. – Arseniy-II Aug 27 '19 at 06:01
  • @Arseniy-II there is huge bunch of code which can confuse you. I've sorted the code related to onBlur and pasted that. And i think the code is working fine. I'm able to call onBlur function after losing focus from the DIV. But it works only after i click on any of the elements inside the div. Because by default it doesnt have the focus. It has focus on the button i clicked to open that DIV. If there is any method to set autofocus on the DIV, that would work i think? – Neel Dsouza Aug 27 '19 at 06:34
  • @Arseniy-II I've updated the code. – Neel Dsouza Aug 27 '19 at 06:41
  • @NeelDsouza Are you expecting `onBlur` event happen when you click inside `
    `?
    – Arseniy-II Aug 27 '19 at 07:11
  • @Arseniy-II yes. – Neel Dsouza Aug 27 '19 at 07:29
  • @NeelDsouza it is not how `blur` event works. It may be very trick especially if you have focusable elements inside. Notice that if you will click inside your `` you will see **second `blur` event**. I'll attach small code example as answer – Arseniy-II Aug 27 '19 at 08:06

1 Answers1

9

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

Arseniy-II
  • 8,323
  • 5
  • 24
  • 49
  • Thats true. When I'm trying to click any of the focusable element inside the DIV even then the DIV's onBlur function will happen, which in my case shouldnt happen. So what can be the best possible solution in this case? – Neel Dsouza Aug 27 '19 at 11:00
  • 1
    @NeelDsouza if you want to prevent `blur` happen on `main` div when you click focusable element inside that div just add `e.stopPropagation();` – Arseniy-II Aug 27 '19 at 11:20
  • Still not working. After losing focus from the textbox and clicking on DIV, the DIV's blur function getting called. – Neel Dsouza Aug 27 '19 at 12:50
  • @NeelDsouza may you update your question with `e.stopPropagation();`? So I can see what may go wrong. – Arseniy-II Aug 28 '19 at 05:47
  • 1
    Updated the question. In the current code, If the focus is on DIV and I try to click textbox, the DIV's blur event fires which in my case shouldn't happen. I want DIV's blur event to fire only when i click outside the DIV and not on any of the elements inside. – Neel Dsouza Aug 28 '19 at 10:54