简体   繁体   中英

Inconsistent focus() with React in Safari/Chrome/Firefox

I recently ran into an issue in React when cross-browser testing. The issue occurs when calling focus() on an element containing React's auto-generated <span> tags.

Simplified Component

My component, a <Button/> , is an abstraction of a normal <button> with additional features. Here's a simplified version:

The output of:

<Button value="Button"/>

is:

<button><span>Button</span></button>

Due to React's auto-wrapping of floating text nodes in a span so it can assign a data-reactid , the text within the <button> is wrapped in <span> tags.

The button has an onClick() method to call event.target.focus() on the element.

The Issue

In Chrome/Firefox clicking the button sets focus on the button. In Safari, clicking the button does not always set focus on the button. Instead the <body> receives focus.

After several hours of fiddling I discovered the button receives focus only when clicked outside of React's auto-generated <span> tags (the blue areas of the button below). Clicking within the <span> tags created by React (the black areas of the button below) will cause the <body> to gain focus.

在此处输入图片说明

Again, this only happens in Safari.

In Chrome/Firefox, clicking either of the areas results in the <button> gaining focus.

Here's a CodePen containing the full example, the steps to reproduce:

  1. Open the CodePen in Safari.
  2. Open your console.
  3. Click the button, within the dark area (corresponding to the <span> tag). You'll notice the focused element (using document.activeElement ) is most likely the <body> .
  4. Click the button, within the blue area (corresponding to the <button> tag. You'll notice the focused element is the <button> .

Question

Is there a preferred method for making the behavior consistent across browsers? Or is this unrelated to React and merely a difference in how Safari/Chrome/Firefox handle focus() ?

One possible solution: set pointer-events: none; on the inner <span> element. This would allow clicks on the <span> to propagate through to the <button> . This seems hackish however.

Can you just use a ref?

aka

something(event){
    this.refs.button.focus()
}
render(){
    // stuff
    return (
        <button ref="button" onClick={this.something}>
            {some text here that will make a span element around it}
        </button>
    );
}

sample fiddle

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM