<star-rating>

by WebComponents

HTML

<star-rating stars=5 rating="3.5"
             bgcolor="green" nocolor="grey" color="gold"></star-rating>
             
<br>

<star-rating stars=7 rating="50%"
             bgcolor="rebeccapurple" nocolor="beige" color="goldenrod"></star-rating>

<h1 id=clicked></h1>

<script>
  document.addEventListener("click", (evt) => clicked.innerHTML="You clicked: "+evt.target.getAttribute("n")+" of "+evt.target.closest("star-rating").stars);
</script>

<b>GZip size & analysis:</b>
<file-size gz src="https://star-rating.github.io/element.js"></file-size>
<script src="https://file-size.github.io/element.js"></script>

CSS

body{
  font:16px Arial;
  background:beige;
}

JavaScript

customElements.define("star-rating", class extends HTMLElement {
    set rating(rate) {
      if (!String(rate).includes("%")) rate = Number(rate) / this.stars * 100 + "%";
      this.querySelector(":nth-child(2)").setAttribute("width", rate); //2nd rect
    }
    connectedCallback() {
      let {bgcolor,stars,nocolor,color,rating} = this.attributes;
      let repeat = (count, func) => Array(count).fill().map(func);
      this.stars = ~~stars.value || 5;
      this.innerHTML = `<svg viewBox="0 0 ${this.stars*100} 100" style=cursor:pointer>` +
        `<rect height=100 fill=${nocolor.value} width=100% />` +
        `<rect height=100 fill=${color.value} />` +
        repeat(this.stars    , (i, n) => `<path fill=${bgcolor.value} d="m${ n*100 } 0h102v100h-102v-100m91 42a6 6 90 00-4-10l-22-1a1 1 90 01-1 0l-8-21a6 6 90 00-11 0l-8 21a1 1 90 01-1 1l-22 1a6 6 90 00-4 10l18 14a1 1 90 010 1l-6 22a6 6 90 008 6l19-13a1 1 90 011 0l19 13a6 6 90 006 0a6 6 90 002-6l-6-22a1 1 90 010-1z"/>`) +
        repeat(this.stars * 2, (i, n) => `<rect x=${ n*50 } n=${n} opacity=0 width=50 height=100 ` +
          ` onclick="this.closest('star-rating').dispatchEvent(new Event('click'))" ` +
          ` onmouseover="this.closest('star-rating').rating=${(n+1)/2}"/>`) +
        "</svg>";
      this.rating = rating.value;
    }
  });