DEV Community

Cover image for Olympic Medal Ranking Web Component
Danny Engelman
Danny Engelman

Posted on • Updated on

Olympic Medal Ranking Web Component

web components - html -javascript

TL;DR

olympic rings divider

The <olympic-medal-ranking> Web Component

  • Web Components/Custom Elements technology is standard technology available in all modern browsers.

  • Web Components are not a toy for developers and can't be compared to other technologies

  • Web Components give power to HTML users! 💪🏽

  • The terms Web Component and Custom Elements are used interchangeably
    Web Components encompass multiple technologies, whereas Custom Elements specifically refer to the API for defining new HTML elements.

All HTML required is:

<script src="https://olympic-medal-ranking.github.io/element.min.js"></script>

<olympic-medal-ranking></olympic-medal-ranking>
Enter fullscreen mode Exit fullscreen mode

To display:

olympic rings divider

Flags are flags are flags?

Like many sites using flags, the Olympic site uses a PNG file for every country flag.
That is 56 files totalling a 103 KB (GZipped) download for the Olympic Medal Ranking page

56 PNG files

olympic rings divider

The FlagMeister Web Component (since 2018)

Many moons ago I created a SINGLE 30 KB Web Component file de-hydrating all country flags as SVG (in IMG tags) (https://flagmeister.github.io/)

FlagMeister flags

All HTML required is:

<script src="https://flagmeister.github.io/elements.flagmeister.min.js" />

<style>
  img { width:100px; border: 1px solid grey }
</style>

<h1><flag-olympic></flag-olympic>Olympic Medal Ranking - Top 5</h1>
<flag-cn></flag-cn>
<flag-fr></flag-fr>
<flag-jp></flag-jp>
<flag-au></flag-au>
<flag-gb></flag-gb>
Enter fullscreen mode Exit fullscreen mode

Every flag Web Component creates additional HTML:

FlagMeister creates HTML

olympic rings divider

Web Components are not like libraries/frameworks

It does not matter when the file defining the Web Component is loaded.
Using a <script> tag it can be placed anywhere in the file.
A import statement can be used at any time.
All existing undefined Elements in the DOM page will automagically upgrade.

Also see CSS :defined - https://developer.mozilla.org/en-US/docs/Web/CSS/:defined

olympic rings divider

Olympics Data

Kevin Le simplified the Olympics Data API to a concise JSON format.

And, on request, within minutes, added ISO-3166-Alpha2 codes to match the flags. Because the IOC - International Olympic Committee uses their own Country Codes that do not 100% match with the ISO standard.

olympic rings divider

The Olympics Medal Rank Web Component

We got Flags and Medal Data;
now a new Web Component can create a Medal Ranking

  • fetch Kevin Le's JSON endpoint
  • loop all records
    • display rank, flag, countryname & medal count

All HTML required is:

<script src="https://olympic-medal-ranking.github.io/element.min.js"></script>

<olympic-medal-ranking></olympic-medal-ranking>
Enter fullscreen mode Exit fullscreen mode

olympic rings divider

The Web Component creates HTML in a shadowDOM/shadowRoot

Web Components can use Shadow DOM to encapsulate content, protecting against global styling and conflicting ID values. This keeps the CSS concise and the HTML code clean, ensuring the Web Component remains small and efficient.

ShadowDOM shown in the console

You can not style shadowDOM with Global CSS!

Bollocks!
You can style shadowDOM, but only the parts the Web Component Author allows you to style with part attributes:

<tr id="CHN" title="China">
  <td class="rank" part="rank">1</td>
  <td class="flag"><flag-cn is="flag-cn" alt="China">...</flag-cn></td> 
  <td part="countrycode"> CHN</td>
  <td part="countryname">China</td>
  <td class="medals gold" part="medal medalgold">11</td>
  <td class="medals silver" part="medal medalsilver">7</td>
  <td class="medals bronze" part="medal medalbronze">3</td>
  <td class="medals total" part="medal medaltotal">21</td>
</tr>
Enter fullscreen mode Exit fullscreen mode

So if the Web Component Author has added plenty of part attributes,
you can use Global CSS

<style id="PARTS">
  olympic-medal-ranking {
    &::part(table) {
        max-width: 550px;
    }
    &::part(header) {
        font-size: 150%;
        color: goldenrod;
        background: lightgrey;
        text-shadow: 1px 1px 1px black;
    }
    &::part(medal) {
        font-weight: bold;
    }
    &::part(rank),
    &::part(countrycode),
    &::part(medaltotal) {
        font-weight: normal;
        color: grey;
    }
  }
</style>
Enter fullscreen mode Exit fullscreen mode

olympic rings divider

Note:

shadowDOM is well over a decade old now.
All <input>, <textarea>, <video> (and more) tags have been using shadowDOM under the hood for many years.
This is a browser-vendor-only version of shadowDOM called user-agent shadowDOM, and can not be styled by Global CSS (unless the Browser Vendor has programmed extra hooks for styling)

user-agent

You can view all User-Agent shadowDOM by activating the console setting:

A filtered ranking for European Union countries

Can be created with HTML attributes flag, total and iocfilter

<olympic-medal-ranking 
 flag="EU" 
 total="all"
 iocfilter="AUT,BEL,BUL,CRO,CYP,CZE,DEN,EST,FIN,FRA,GER,GRE,HUN,IRL,ITA,LAT,LTU,LUX,MLT,NED,POL,POR,ROU,SVK,SLO,ESP,SWE"
>European Union Medal Ranking</olympic-medal-ranking>
Enter fullscreen mode Exit fullscreen mode

And EU styling for the <thead>

<style>
  olympic-medal-ranking[flag="EU"] {
    &::part(thead) {
      background: #003399;
    }
    &::part(header) {
      background: inherit;
      color: gold;
      font-weight: bold;
    }
  }
</style>
Enter fullscreen mode Exit fullscreen mode

Filtered EU ranking

olympic rings divider

If you do want the source...

This was it, a blog-post for HTML Users, no JavaScript code displayed

The Web Component source code is at:
https://github.com/olympic-medal-ranking/olympic-medal-ranking.github.io

It has the Unlicense; so you can do whatever you want with it

Or fork the JSFiddle with JavaScript source for the Component:

olympic rings divider




Top comments (0)