2

I can't seem to find anyone with this same issue online with React, unless I've been searching for the wrong thing?

I have a button (anchor tag) that has an onClick event. When the onClick event is triggered it calls a loadMore() function that makes an API call and updates some state.

However on a mobile device (not mobile resolution on desktop!) when I click the button, the onClick event works and returns what is expected, however it applies a hover state on the button. For the button hover state I have a background color applied

The hover state will stick until I click away anywhere else on the screen. So the background color sticks until I click away.

Now, this isn't exactly desirable. Why is this happening, and how did I prevent it?

Here is my Button Component

const Button = props => {
  const buttonDisabledClass = props.disabled ? "Button--disabled " : "";
  const hiddenClass = props.hidden ? "Button--hidden " : "";
  const modifierClass = props.modifier ? props.modifier : "";

  return (
    <>
      <a
        onClick={!props.disabled ? props.onClick : undefined}
        className={
          "Button " + buttonDisabledClass + hiddenClass + modifierClass
        }
      >
        {props.children}
        {props.buttonText ? (
          <span
            className={`Button-text ${
              props.buttonMobileText ? "Button-desktopText" : ""
            }`}
          >
            {props.buttonText}
          </span>
        ) : null}
        {props.buttonMobileText ? (
          <span className="Button-mobileText">{props.buttonMobileText}</span>
        ) : null}
      </a>
    </>
  );
};

Here is the parent component

The parent component imports the Button component and has the function that makes the API request (just have a simulated one here as an example)

function App() {
  const [number, setNumber] = useState(0);

  /*simulate http request*/
  const ttl = 500;
  const loadMore = () => {
    const timeout = setTimeout(() => {
      setNumber(number + 1);
    }, ttl);
    return () => {
      clearTimeout(timeout);
    };
  };

  return (
    <div className="App">
      {number}
      <Button
        key={"loadMoreBtn"}
        modifier="Button--loadMore Button--Inline"
        onClick={() => loadMore()}
      >
        Load More
      </Button>
    </div>
  );
}

So, how can I make it so a click on a mobile device does not register hover but still have the hover working on a desktop device as it currently is?

I have a CODESANDBOX if you wish to test it out for yourself

Here is a link for you to test on your mobile device.

The button is orange by default, and grey on hover. On mobile, this is what happens when you click...enter image description here

Any help would be greatly appreciated!

Community
  • 1
  • 1
mcclosa
  • 943
  • 7
  • 29
  • 59
  • Sounds more like a focus state than a hover state.. – Keith Apr 26 '19 at 13:18
  • @Keith Opening up the dev tools, I can see that `.Button:hover` is applied, not focus – mcclosa Apr 26 '19 at 13:19
  • This is a normal behavoir for most mobile browsers. Have a look at [this question](https://stackoverflow.com/questions/17233804/how-to-prevent-sticky-hover-effects-for-buttons-on-touch-devices) or [this article](http://www.javascriptkit.com/dhtmltutors/sticky-hover-issue-solutions.shtml#dynamichover) – Wendelin Apr 26 '19 at 13:24
  • @Wendelin May be normal behaviour, but not desired in this case, I am looking at a method to prevent this from happening. Due to the colour scheme, we need to use, the grey button makes it look disabled which will confuse the end user – mcclosa Apr 26 '19 at 13:26
  • I'd would suggest you disable the hover state for mobile devices, doesn't really make much sense on mobile anyway. – Keith Apr 26 '19 at 13:26
  • @mcclosa The article and the question that I have linked show many solutions for this problem – Wendelin Apr 26 '19 at 13:27
  • @Wendelin Thanks, didn't see your updated comment when I had commented, I'll check them out – mcclosa Apr 26 '19 at 13:28

1 Answers1

1

You could override the hover effect on mobile using a media query in your CSS:

@media only screen and (min-resolution: 117dpi) and (max-resolution: 119dpi), only screen and (min-resolution: 131dpi) and (max-resolution: 133dpi), only screen and (min-resolution: 145dpi) and (max-resolution: 154dpi), only screen and (min-resolution: 162dpi) and (max-resolution: 164dpi), only screen and (min-resolution: 169dpi) {
  .Button:hover {
    background-color: #ee4900 !important;
  }
}

Or

@media (hover: none) {
  .Button:hover {
    background-color: #ee4900 !important;
  }
}
Jobokai
  • 313
  • 1
  • 5
  • 19
  • This would still occur on Large tablets, especially in landscape. Then there are some people who will have small resolution monitors at the same width as that and I'd like for them to still be able to hover. – mcclosa Apr 26 '19 at 13:37
  • 2
    @mcclosa you can replace the `(max-width: 480px)` with `(hover: none)` to only target touch devices (e.g. devices without hover). See: https://css-tricks.com/touch-devices-not-judged-size/ – elveti Apr 26 '19 at 13:40
  • 1
    I updated my answer to use a few dpi tricks that I had found, but @elveti also mentioned an alternative. – Jobokai Apr 26 '19 at 13:41
  • 1
    @elveti I had actually tried `(hover: hover)` to just apply the hover on desktop devices but did not work on IE (unfortunately have like 18% of our users are using IE so have to support at least IE9) but using `(hover: none)` and applying the default background colour actually works. Thank you! – mcclosa Apr 26 '19 at 13:46
  • 1
    @mcclosa funny, just an hour ago another user had the same problem and he found a solution https://stackoverflow.com/a/55867559/1498053 So for future references you can use `@media (hover: hover), (-ms-high-contrast:none)` to at least support until IE11 – elveti Apr 26 '19 at 13:59