DEV Community

Cover image for Radio Component with RiotJS (Material Design)
Steeve
Steeve

Posted on • Updated on

Radio Component with RiotJS (Material Design)

This article covers creating a Riot Radio 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/

A Radio is often part of a group of Radio buttons: Only one radio button in a given group can be selected simultaneously (see the following screenshot). The goal is to create a Radio component with BeerCSS design and listen to change events.

Radio elements from the BeerCSS documentation

Note: The article doesn't cover how to create a radio as an Icon or as an Image.

Radio Component Base

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

Write the following HTML code (found on the BeerCSS documentation) in ./components/c-radio.riot:

<c-radio >
    <label class="radio">
        <input type="radio" name={ props?.name } value={ props?.defaultValue } checked={ props?.defaultValue === props?.value } disabled={ props?.disabled }>
        <span>
            <slot></slot>
        </span>
    </label>
</c-radio>
Enter fullscreen mode Exit fullscreen mode

Let's break down the code:

  • The <c-radio> and </c-radio> defined a custom root tag, with the same name as the file. You must write it; otherwise, it may create unexpected results. Using the <label> as a root tag or redefining native HTML tags is a bad practice, so starting c- is a good naming.
  • A name attribute is required for each Radio: Radios of the same group must have the same name.
  • The radio takes two different values attributes:
    • The default-value attribute defines the radio value.
    • the value attribute defines the value of the group.
  • To enable the checked attribute, the value of the group must be equal to the radio default value default-value.
  • A radio can have a label; it must be passed as a Slot, a Riot tag to inject HTML templates in a child component from its parent.
  • The element is disabled if the props.disabled attribute exists and the value is true.

Now to create a radio group, let's create a parent component named ./components/c-radio-group.riot. The following HTML was copied from the BeerCSS documentation, and RiotJS logic was added:

<c-radio-group class="field middle-align">
    <nav>
        <slot></slot>
    </nav>
    <span class="helper" if={ props?.helper && !props?.error }>{ props.helper} </span>
    <span class="error" if={ props?.error }>{ props.error}</span>
</c-radio-group>
Enter fullscreen mode Exit fullscreen mode
  • To define multiple Radio components in the group, Radios are injected thanks to the <slot></slot> tag: The Slot tag is a special Riot.js core feature that allows you to inject and compile the content of any custom component.
  • The helper span is displayed if the helper attribute exists.
  • If the error attribute exists, the error span is displayed and the helper is hidden.

Finally, load and instantiate the c-radio.riot and c-radio-group.riot, in a front page named index.riot:

<index-riot>
    <div style="width:600px;padding:20px;">
        <h4 style="margin-bottom:20px">Riot + BeerCSS</h4>
        <c-radio-group oninput={ changed }>
            <c-radio default-value="blue" value={ state.value } name="color">Blue</c-radio>
            <c-radio default-value="red" value={ state.value } name="color">Red</c-radio>
            <c-radio default-value="green" value={ state.value } onclick={ clicked } name="color">Green</c-radio>
        </c-radio-group>
        Selected: { state.value }
    </div>
    <script>
        import cRadio from "./components/c-radio.riot";
        import cRadioGroup from "./components/c-radio-group.riot"

        export default {
            components: {
                cRadio,
                cRadioGroup
            },
            state: {
                value: "green"
            },
            changed (ev) {
                this.update({ value: ev.target.value })
            }
        }
    </script>
</index-riot>
Enter fullscreen mode Exit fullscreen mode

Code details:

  1. Components are imported with import cRadio from "./components/c-radio.riot"; and import cRadioGroup from "./components/c-radio-group.riot" then loaded in the components:{} Riot object.
  2. The component RadioGroup is instantiated with <c-radio-group></c-radio-group> on the HTML.
  3. The component Radio is instantiated within the Radio group as a Slot, such as: <c-radio-group><c-radio>label<c-radio></c-radio-group>.
  4. Each Radio gets the same group name: color.
  5. Each Radio gets a default value with the attributes name default-value: red, green or blue.
  6. The state of the radio group is stored in the state Riot object state: { value: 'green' }. Green is the default value.
  7. If a click is made on the Radio group, the change event is fired, and the changed function is executed to update the value of the group state.value.
  8. To update a state, you must use the update() Riot function, such as: this.update({ value: ev.target.value }). The state.value gets the Radio change event value.

Here is the generated HTML:

Image description

Radio Component Testing

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

Conclusion

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

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

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

Have a great day! Cheers 🍻

Top comments (0)