Chip Component with RiotJS (Material Design)
Tags: riotjs, javascript, beginners, frontend
Published: 2024-03-31 16:01:09

This article covers creating a Riot Chip 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](https://dev.to/steeve/riotjs-material-design-how-to-setup-beercss-269c).

> These articles form a series focusing on [RiotJS](https://riot.js.org/) paired with [BeerCSS](https://www.beercss.com/), 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/

Chips help people enter information, make selections, filter content, or trigger actions (see the following screenshot). The goal is to create a Chip Riot component that supports all styling and listens to click events.

![Chips example from the material.io documentation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kivm5ebitqk21y110jxd.png)

## Chip Component Base

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

Into **./components/c-chip.riot**, write the following HTML (found in the [BeerCSS documentation](https://www.beercss.com/#chips)):
```html
<c-chip>
    <a class="
            chip
            {props?.small ? 'small' : null }
            {props?.medium ? 'medium' : null }
            {props?.large ? 'large' : null }

            {props?.smallElevate ? 'small-elevate' : null}
            {props?.mediumElevate ? 'medium-elevate' : null}
            {props?.largeElevate ? 'large-elevate' : null}

            {props?.round ? 'round' : null }
            {props?.fill ? 'fill' : null }
            {props?.vertical ? 'vertical' : null }
        ">
        <i if={ props?.icon }>{ props.icon }</i>
        <img class={props?.inline ? null : "responsive" } if={ props?.img } src={ props.img }>
        <span><slot></slot></span>
        <i if={ props?.iconend }>{ props.iconend }</i>
    </a>
</c-chip>
```
Let's break down the code:
1. The `<c-chip>` and `</c-chip>` defined a custom root tag, with the same name as the file. You must write it; otherwise, it may create unexpected results. Using the `<a>` 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: we will inject the chip's label.
3. A chip has many variations classes: size, elevation and form (round, fill or vertical). It is injected conditionally if the corresponding props exist. For instance, if the property `props.round` exists, it will enable the `round` class in the component.
4. Two icons can be passed at two positions: either as a prefix or as a suffix of the label:
  * the property `icon` injects the glyph before the label
  * the property `iconend` injects the glyph after the label
5. Thanks to the `img` property, an image can be injected instead of an icon.

Finally, the **c-chip.riot** can be instantiated into a front page **index.riot**. Here are all Chip variations, either filled, rounded, including an image or icon:
```html
<index-riot>
    <div style="width:800px;padding:20px;">
        <h4 style="margin-bottom:20px;margin-left:10px;">Riot + BeerCSS</h4>
        <h6 style="margin-left:10px">Chip Variations</h6><br>
        <c-chip>Suggestion</c-chip>
        <c-chip iconend="close">Input</c-chip>
        <c-chip icon="check">filter</c-chip>
        <c-chip icon="today">assist</c-chip>
        <c-chip img="./favicon.png" inline="true">image</c-chip>
        <c-chip img="./favicon.png">image</c-chip>
        <br><br>
        <c-chip round="true">Suggestion</c-chip>
        <c-chip round="true" iconend="close">Input</c-chip>
        <c-chip round="true" icon="check">filter</c-chip>
        <c-chip round="true" icon="today">assist</c-chip>
        <c-chip round="true" img="./favicon.png" inline="true">image</c-chip>
        <c-chip round="true" img="./favicon.png">image</c-chip>
        <br><br>
        <c-chip fill="true">Suggestion</c-chip>
        <c-chip fill="true" iconend="close">Input</c-chip>
        <c-chip fill="true" icon="check">filter</c-chip>
        <c-chip fill="true" icon="today">assist</c-chip>
        <c-chip fill="true" img="./favicon.png" inline="true">image</c-chip>
        <c-chip fill="true" img="./favicon.png">image</c-chip><br><br>
        <c-chip fill="true" round="true">Suggestion</c-chip>
        <c-chip fill="true" round="true" iconend="close">Input</c-chip>
        <c-chip fill="true" round="true" icon="check">filter</c-chip>
        <c-chip fill="true" round="true" icon="today">assist</c-chip>
        <c-chip fill="true" round="true" img="./favicon.png" inline="true">image</c-chip>
        <c-chip fill="true" round="true" img="./favicon.png">image</c-chip>
    </div>
    <script>
        import cChip from "./components/c-chip.riot"

        export default {
            components: {
                cChip
            },
        }
    </script>
</index-riot>
```
Code break-down:
1. The component is imported with `import cChip from "./components/c-chip.riot";` then loaded into the **components:{}** Riot object.
2. On the HTML, the Chip component is instantiated with `<c-chip>label<c-chip>`
3. Pass attributes to the tag to enable variations, for instance: `<c-chip fill="true" round="true" icon="check">filter</c-chip>`.

Screenshot of the generated HTML:
![Variations of the chip Component made with RiotJS and BeerCSS](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/msfo8g4wh83phx41r1u4.png)

## Chip Component Events

As mentioned, a chip is used to filter, suggest and trigger actions. A real-world example would be that you must select your flat's amenities for a rental application.

Let's make a group of chips for each amenity and check if it is selected.

![Chip group listening to click events](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vkn7i2hic0a10xyet25g.gif)

Here is the corresponding HTML and Riot code in the **index.riot**:
```html
<index-riot>
    <div style="width:800px;padding:20px;">
        <h6 style="margin-left:10px">Amenities</h6><br>
        <c-chip each={ el in state.amenities } onclick={ (ev) => clicked(el.label) } fill={ el.checked === true } icon={ el.checked === true ? 'check' : null }> { el.label } </c-chip>
    </div>
    <script>
        import cChip from "./components/c-chip.riot"

        export default {
            components: {
                cChip
            },
            state: {
                amenities: [
                    { label: "Wash / Dryer", checked: false },
                    { label: "Ramp Access", checked: false },
                    { label: "Garden", checked: false },
                    { label: "Cat OK", checked: false }
                ]
            },
            clicked (label) {
                const _el = this.state.amenities.find(el => el.label === label);
                if (_el) {
                    _el.checked = !_el.checked;
                    this.update();
                }
            }
        }
    </script>
</index-riot>
```
Code details:
1. A list of Chips is printed thanks to the [Each](https://riot.js.org/documentation/#loops) Riot attribute.
2. Each chip is listening to a click event with `onclick={ (ev) => clicked(el.label) }`. If a click event is fired, the function `clicked` is executed, and the label is passed as first argument.
3. The `clicked` function finds the list item based on the label, then the `checked` property is updated.
4. When the `checked` is true, two attributes are enabled **fill** and **icon**.

## Chip Component Testing

It exists two methods for testing the Chip component, and it is covered in two different articles:
* [Test with Vitest and Riot-SSR in a Node Environment](https://dev.to/steeve/riot-component-unit-test-with-vitest-node-env-hk0)
* [Test with Vitest in a JsDom Environment](https://dev.to/steeve/riot-component-unit-test-with-vitest-jsdom-env-182l)

## Conclusion

Voilà 🎉 We created a Chip Riot Component using Material Design elements with BeerCSS. 

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

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

Have a great day! Cheers 🍻