Jimmy
Jimmy

Reputation: 3860

Element focus when hover

I want to create a button whose styling changes on a hover and stays that way until another hover occurs. Essentially, I want to create a button whose focus is changed by a hover, as seen here. I think I can do this with some functions changing the state between the parent and child, but is there a more simple way of doing this? Thanks.

class Button extends React.Component {
  render() {
    return (
      <button>{this.props.title}</button>
    );
  }
}

class Parent extends React.Component {
  render() {
    return (
      <div>
        <Button title={"button 1"}/>
        <Button title={"button 2"}/>
        <Button title={"button 3"}/>
      </div>
    );
  }   
}



ReactDOM.render(<Parent />, app);
button:hover {
  background-color: yellow;
}
<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>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="app"></div>

Upvotes: 0

Views: 1636

Answers (2)

Ori Drori
Ori Drori

Reputation: 191976

The Parent is the only place that knows the buttons, and since the active change needs to be persistent, you'll need to change the state:

class Button extends React.Component {
  onHover = () => this.props.onHover(this.props.buttonId);

  render() {
    const { title, activeId, buttonId } = this.props;
    
    return (
      <button onMouseOver={this.onHover} 
        className={ activeId === buttonId ? 'active' : '' }>
        {title}
      </button>
    );
  }
}

class Parent extends React.Component {
  constructor(props) {
    super(props);
    
    this.state = {
      activeId: null
    }
  }
  
  onButtonHover = (activeId) => this.setState({ activeId });

  render() {
    const { activeId } = this.state;
    
    return (
      <div>
        <Button title={"button 1"} 
          onHover={this.onButtonHover} 
          buttonId={0}
          activeId={ activeId } />
        <Button title={"button 2"} 
          onHover={this.onButtonHover} 
          buttonId={1}
          activeId={ activeId } />
        <Button title={"button 3"} 
          onHover={this.onButtonHover} 
          buttonId={2}
          activeId={ activeId } />
      </div>
    );
  }   
}



ReactDOM.render(<Parent />, app);
.active {
  background-color: yellow;
}
<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>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="app"></div>

Upvotes: 1

user8811940
user8811940

Reputation:

Here you have a possible CSS only solution: https://jsfiddle.net/ggcybu71/

.option:hover {
    text-decoration: underline;
}
.option:hover:after {
    content: "";
    display: block;
    position: fixed;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    z-index: -1;
}

It is way too "hacky", so I would only see it as a curiosity and I would probably not use it in production. I would implement a Javascript based mousemove event listening solution instead.

Upvotes: 0

Related Questions