2

I need to move menu item underline like in this example.

With jQuery I would do it simply getting left position and width of a menu item. And then perform stop.animation on hover.

I'm trying to do such animation with React. But I can't figure out how to. After google research I found the popular react-motion library for animation. But I can't find the way how to trigger animation on hover.

My task is move blue underline on div hover. Please help me to find the solution.enter image description here

Nastro
  • 1,719
  • 7
  • 21
  • 40

2 Answers2

6

You can do this using a css transition and an absolutely positioned stripe for the under line. Then update the left property of the stripe when the element is hovered.

class App extends React.Component {
  constructor() {
    super()
    this.state = {
      left: 0,
    }
  }
  
  handleMouseEnter = (e) => {
    this.setState({
      left: e.target.getBoundingClientRect().x - 8,
    });
  }

  render() {
    return (
      <div className="App">
        <div className="box" onMouseEnter={this.handleMouseEnter} />
        <div className="box" onMouseEnter={this.handleMouseEnter}  />
        <div className="box" onMouseEnter={this.handleMouseEnter}  />
        <div className="box" onMouseEnter={this.handleMouseEnter}  />
        <div className="stripe" style={{ left: this.state.left }}/>
      </div>
    );
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);
.App {
  width: 900px;
  overflow: hidden;
  position: relative;
  padding-bottom: 20px;
}
.box {
  width: 200px;
  height: 200px;
  background: #eee;
  border: 1px solid #333;
  float: left;
  margin-right: 10px;
}
.stripe {
  width: 200px;
  height: 10px;
  background: blue;
  position: absolute;
  bottom: 0;
  transition: left 0.3s;
}
<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>
<div id="root"></div>

Here is an example on codepen

spirift
  • 2,994
  • 1
  • 13
  • 18
  • Thank you! Working, so simple! – Nastro Oct 03 '18 at 08:41
  • Very useful. If your items/boxes have different widths, you can also update the width of the stripe in the mouseEnter handler ```handleMouseEnter = (e) => { this.setState({ left: e.target.getBoundingClientRect().x - 8, width: e.target.offsetWidth }); }``` – jtrezza Jun 02 '21 at 18:47
  • Note that your solution will mess the stripe's position when you scroll. I haven't noticed initially but when I ran your inline snippet on SO and scrolled the iframe, it immediately moved it to the wrong position. – Silviu Burcea Sep 29 '21 at 12:48
  • See more on MDN: https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect It's relative to the viewport. – Silviu Burcea Sep 29 '21 at 12:53
-2

You don't really have to do it with React. It can be achieved with box-shadow, if you don't mind the underline being right under the box. It also allows you to blur it a little bit for more styling.

.App {
  width: 900px;
  overflow: hidden;
  position: relative;
  padding-bottom: 20px;
}
.box {
  width: 200px;
  height: 200px;
  background: #eee;
  border: 1px solid #333;
  float: left;
  margin-right: 10px;
}

.box:hover {
  box-shadow: 0 10px blue;
  transition: box-shadow 0.3s;
}
<div class="App">
  <span class="box"></span>
  <span class="box"></span>
  <span class="box"></span>
  <span class="box"></span>
</div>
Silviu Burcea
  • 5,103
  • 1
  • 29
  • 43
  • The author is asking explicitly for a React-based solution. – nicoramirezdev Sep 16 '21 at 17:45
  • @kamatheuska Seriously?! This works in React as well. I just haven't put my code in a `render()` function. Also, rule of thumb, if it can be done without JS easily, don't do it in JS. – Silviu Burcea Sep 20 '21 at 10:09
  • Although your answer might be valid in some scenarios, there is use cases for triggering an action `onmouseenter` with React, not depending on CSS. For example when a side effect is needed in the UI. So this answer is not covering that, so IMO should not be upvoted in this case. – nicoramirezdev Sep 24 '21 at 18:33
  • @kamatheuska Fair enough. However, what you're saying is not what OP asked for. He asked just for bottom border on hover. I can also add `onMouseEnter` as well for side effects, there's nothing stopping you from doing that, but this is not mentioned in the question. I have provided a YAGNI type of response. – Silviu Burcea Sep 28 '21 at 07:32
  • Think about what makes someone come to this answer. That would be the title, where REACT is clearly a requirement. So yes, he did ask for react related answer. It is in the title. – nicoramirezdev Sep 28 '21 at 12:53
  • @kamatheuska I disagree. OP uses React, true, but many questions include unnecessary (or to the contrary, insufficient) informations and are later refined. React is not needed for the task being requested. Even so, can you use my answer in a web app built with React to solve OP's requirements? Yes. – Silviu Burcea Sep 29 '21 at 06:15
  • Well, I agree your solution is quite neat for an animation that does not require JS but lacks what the OP's title states, which is a React-based answer. You may interpret that he does not need React, but that is not stated on the question though...maybe if you convince OP to change the question approach your solution would be a good fit. – nicoramirezdev Sep 29 '21 at 10:44