Icon Component with RiotJS (Material Design)

Steeve - Mar 25 - - Dev Community

This article covers creating a Riot Icon component, using the Material Design CSS BeerCSS. Before starting, make sure you have a base application running, or read my previous article Setup Riot + BeerCSS + Vite.

These articles form a series focusing on RiotJS paired with BeerCSS, designed to guide you through creating components and mastering best practices for building production-ready applications. I assume you have a foundational understanding of Riot; however, feel free to refer to the documentation if needed: https://riot.js.org/documentation/

There are three types of icons on BeerCSS: default using Google Material Glyphs, SVG, or as an image (see following screenshot). The goal is to create an icon Riot component that supports all three formats and listens to click events.

Icons from the BeerCSS documentation

Icon Component Base

First, create a new file named c-icon.riot under the components folder. The c- stands for "component", a useful naming convention and a good practice.

Into ./components/c-icon.riot, write the following HTML (found on the BeerCSS documentation):

<c-icon>
    <i class="
        { props?.tiny ? ' tiny' : null}
        { props?.small ? ' small' : null}
        { props?.large ? ' large' : null}
        { props?.extra ? ' extra' : null}

        { props?.fill ? ' fill' : null}

        { props?.primary ? ' primary-text' : null}
        { props?.secondary ? ' secondary-text' : null}
        { props?.tertiary ? ' tertiary-text' : null}
    ">
        <slot></slot>
    </i>
</c-icon>
Enter fullscreen mode Exit fullscreen mode

Let's break down the code:

  1. The <c-icon> and </c-icon> defined a custom root tag, with the same name as the file. You must write it; otherwise, it may create unexpected results. Using the as a root tag or redefining native HTML tags is a bad practice, so starting c- is a good naming.
  2. Using the <slot> tag you can inject custom HTML templates in a child component from its parent: Now we can inject either a string (for Google Material Icon), an SVG tag, or an image tag.
  3. A BeerCSS icon supports different sizes and theme classes: Each class is applied conditionally if the corresponding props exists. Properties are defined on the HTML attribute name.

Finally, the c-icon.riot can be instantiated into a front page index.riot:

<index-riot>
    <div style="width:600px;padding:20px;">
        <h4 style="margin-bottom:20px">Riot + BeerCSS</h4>

        <c-icon>check_circle</c-icon>
        <c-icon large="true">
            <svg viewBox="0 0 24 24">
                <path d="M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M7.07,18.28C7.5,17.38 10.12,16.5 12,16.5C13.88,16.5 16.5,17.38 16.93,18.28C15.57,19.36 13.86,20 12,20C10.14,20 8.43,19.36 7.07,18.28M18.36,16.83C16.93,15.09 13.46,14.5 12,14.5C10.54,14.5 7.07,15.09 5.64,16.83C4.62,15.5 4,13.82 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,13.82 19.38,15.5 18.36,16.83M12,6C10.06,6 8.5,7.56 8.5,9.5C8.5,11.44 10.06,13 12,13C13.94,13 15.5,11.44 15.5,9.5C15.5,7.56 13.94,6 12,6M12,11A1.5,1.5 0 0,1 10.5,9.5A1.5,1.5 0 0,1 12,8A1.5,1.5 0 0,1 13.5,9.5A1.5,1.5 0 0,1 12,11Z"></path>
            </svg>
        </c-icon>
        <c-icon extra="true">
              <img src="/favicon.png">
        </c-icon>
    </div>
    <script>
        import cIcon from "./components/c-icon.riot";

        export default {
            components: {
                cIcon
            }
        }
    </script>
</index-riot>
Enter fullscreen mode Exit fullscreen mode

Code break-down:

  1. The component is imported with import cIcon from "./components/c-icon.riot"; then loaded into the components:{} Riot object.
  2. On the HTML, the Icon component is instantiated with <c-icon>icon_name<c-icon>
  3. Since the component uses a slot, different types of icons can be passed: as an SVG or as an image.
  4. If the icon is coming from Google Material Fonts, and if the icon name has a space character in it, replace each space with an underscore. For instance, if the name on Google Font is "Chevron Right", you must write on the slot: chevron_right.

Screenshot of the generated HTML:

Image description

To apply different icon sizes and themes, pass the following attributes to the component tag definition: tiny, small, large, extra, primary, secondary, tertiary, or fill, such as:

<c-icon tiny="true">check_circle</c-icon>
<c-icon small="true">check_circle</c-icon>
<c-icon>check_circle</c-icon>
<c-icon large="true">check_circle</c-icon>
<c-icon extra="true">check_circle</c-icon>
<c-icon extra="true" fill="true">check_circle</c-icon>
<c-icon extra="true" fill="true" primary="true">check_circle</c-icon>
<c-icon extra="true" fill="true" secondary="true">check_circle</c-icon>
<c-icon extra="true" fill="true" tertiary="true">check_circle</c-icon>
Enter fullscreen mode Exit fullscreen mode

The generated HTML of icon variations:

Icons variation of the Icon Component made with Riot

Icon Component Testing

It exists two methods for testing the Icon component, and it is covered in two different articles:

Conclusion

Voilà 🎉 We created an Icon Riot Component using Material Design elements with BeerCSS.

The source code of the icon is available on Github:
https://github.com/steevepay/riot-beercss/blob/main/components/c-icon.riot

Feel free to comment if you have questions or need help about RiotJS.

Have a great day! Cheers 🍻

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .