Search code examples
javascriptcssreactjssvgreact-icons

Is it possible to only show half of a SVG icon?


I currently have a rating system that produces 5 stars that can show half values. I did this by using FontAwesome's Half Stars and did some CSS tricks to make them look like one star. But I was thinking of increasing my React and CSS knowledge by coming up with a way to show only half of an SVG icon. So instead of using the Half Stars, I could use whatever Icon the user wanted, and it would only show 50% of the Icon for example if you wanted to give a 3.5 rating.

Q: Can you show only half of an Icon and somehow know if the user is clicking on one side or the other?

Here is the code I have currently that uses the HalfStars for a little bit of reference

import React, { useState } from 'react'
import { FaRegStarHalf, FaStarHalf } from 'react-icons/fa'

import './styles/Rater.css'

const Rater = ({ iconCount }) => {
    const [rating, setRating] = useState(null)
    const [hover, setHover] = useState(null)
    // check if user has set a rating by clicking a star and use rating to determine icons
    const Star = rating ? FaStarHalf : FaRegStarHalf

    return (
        <div>
            {[...Array(iconCount), ...Array(iconCount)].map((icon, i) => {
                const value = (i + 1) / 2

                return (
                    <label>
                        <input
                            type='radio'
                            name='rating'
                            value={value}
                            onClick={() => {
                                console.log(`value => `, value)
                                return setRating(value)
                            }}
                        />
                        <div className='star-container'>
                            <div>
                                <Star
                                    className={i % 2 ? 'star-left' : 'star'}
                                    color={value <= (hover || rating) ? '#ffc107' : '#e4e5e9'}
                                    onMouseEnter={() => setHover(value)}
                                    onMouseLeave={() => setHover(null)}
                                />
                            </div>
                        </div>
                    </label>
                )
            })}
        </div>
    )
}

export default Rater



Solution

  • I have written a code to get you the idea; If you click on the right side of the star, its color changes to blue and if you click on the left side, its color changes to gold. Also, it's better to not use stopPropagation and check e.target of the event.

    const starIcon = document.getElementById("star");
    const icon = document.getElementById("icon");
    starIcon.onclick = e => {
      starIcon.style.color = "blue";
      e.stopPropagation();
    };
    icon.onclick = e => {
      starIcon.style.color = "gold";
    }
    i {
      clip-path: inset(0 0 0 50%);
      color: gold;
    }
      <!DOCTYPE html>
      <html lang="en">
    
        <head>
          <meta charset="UTF-8">
          <title>Document</title>
          <link href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" rel="stylesheet">
        </head>
    
        <body>
          <span id="icon"><i id="star", class="fas fa-star"></i></span>
        </body>
    
      </html>