Search code examples
cssreactjsnpmcomponentsfocus

Why the `:focus` pseudo-class has no effect on some components in ReactJs?


I am implementing a simple Emoji-Rating system. There are 5 Emojis on the screen, when the user hovers over their appearance changes. It is done by the :hover pseudo-class. And what I wanted is also that when the user clicks on one of the emojis it stays as it was when hovered. But anytime I click on on it and the cursor gets off, it snaps back to ita original look.

Here is the Form in ReactJs:

<form className='ratingForm' onSubmit={(event) => handleSubmit(event)}>
            <div className='inputs'>
              <div className='inputWrapper'>
                <div id="angry-emoji-wrapper" className='emoji-wrapper angry'>
                  <EmojiAngry passedProp={getChildProps} value={0} />
                </div>
                <label className='inpLabel' htmlFor="0">Very Bad</label>
              </div>
              <div className='inputWrapper'>
                <div id="frown-emoji-wrapper" className='emoji-wrapper frown'>
                  <EmojiFrown passedProp={getChildProps} value={1} />
                </div>
                <label className='inpLabel' htmlFor="1">Bad</label>
              </div>
              <div className='inputWrapper'>
                <div id='neutral-emoji-wrapper' className='emoji-wrapper neutral'>
                  <EmojiNeutral passedProp={getChildProps} value={2} />
                </div>
                <label className='inpLabel' htmlFor="2">Average</label>
              </div>
              <div className='inputWrapper'>
                <div id='smile-emoji-wrapper' className='emoji-wrapper smile'>
                  <EmojiSmile passedProp={getChildProps} value={3} />
                </div>
                <label className='inpLabel' htmlFor="3">Good</label>
              </div>
              <div className='inputWrapper'>
                <div id='laughing-emoji-wrapper' className='emoji-wrapper laugh'>
                  <EmojiLaughing passedProp={getChildProps} value={4} />
                </div>
                <label className='inpLabel' htmlFor="4">Very Good</label>
              </div>
            </div>
            <button className='btn btn-success' type="submit">Submit</button>
          </form>

One of the Emoji components using react-icons npm package:

import { BsEmojiAngryFill } from 'react-icons/bs';

export default function EmojiAngry(props) {

    function handleClick() {
        props.passedProp(props.value);
    }

    return (
        <BsEmojiAngryFill onClick={handleClick} />
    )
}

And here is the CSS for it:

/*==================================EMOJI===================================*/
svg {
  width: 70px;
  height: 50px;
  color: rgb(201, 201, 201);
}

/*ANGRY*/
#angry-emoji-wrapper.emoji-wrapper.angry:hover>svg,
#angry-emoji-wrapper.emoji-wrapper.angry:focus>svg {
  color: #de332b !important;
  transform: scale(1.2) !important;
  transition: all .1s ease-in-out !important;
  cursor: pointer !important;
}

I have tried using tabIndex={0} but all I achieved was an outline that kept changing size depending on the emoji's current scale. I have tried writing different css, so not like just separate the hover and focuse with comas. And also I have tried using the :active pseudo as well but nothing.


Solution

  • Looks like I managed to solve it by adding a new class based on whether the emoji is clicked or not and then use that in css.

    Looks like this (not exactly its just a part of it)

    const [selectedEmoji, setSelectedEmoji] = useState(null);
    
    function getChildProps(value) {
    setRating(value);
    setSelectedEmoji(value);
    console.log(value)
    }
    
    <div className={`inputWrapper`}>
                <div id="angry-emoji-wrapper" className={`emoji-wrapper angry ${selectedEmoji === 0 ? 'selected' : ''}`}>
                  <EmojiAngry passedProp={getChildProps} value={0} />
                </div>
                <label className='inpLabel' htmlFor="0">Very Bad</label>
              </div>
    

    The component itself has not changed. And this is the CSS:

    /*==================================EMOJI===================================*/
    svg {
      width: 70px;
      height: 50px;
      color: rgb(201, 201, 201);
    }
    
    /*ANGRY*/
    #angry-emoji-wrapper.emoji-wrapper.angry:hover>svg,
    #angry-emoji-wrapper.emoji-wrapper.angry:focus>svg,
    #angry-emoji-wrapper.emoji-wrapper.angry.selected>svg {
      color: #de332b !important;
      transform: scale(1.2) !important;
      transition: all .1s ease-in-out !important;
      cursor: pointer !important;
    }