This article covers creating a Riot Dialog component, using the Material Design CSS BeerCSS, and reacting to click events.
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/
The Dialog, informs users about a specific task and may contain critical information, require decisions, or involve multiple tasks. In a modal dialog, the user is interrupted and interacts with the dialog before they can continue interacting with the rest of the application, for instance choosing a phone ringtone:
Dialog Component Base
The goal is to create a Riot app with a Dialog and execute an action if the modal is cancelled or confirmed.
First, create a new file named c-dialog.riot
under the components folder. The c-
stands for "component", a helpful naming convention and a good practice.
Write the following HTML code (found on the BeerCSS documentation) in ./components/c-dialog.riot
:
<c-dialog>
<dialog class="
{props?.active ? 'active ' : null}
{props?.blur ? 'overlay blur ' : null}
{props?.left ? 'left ' : null}
{props?.right ? 'right ' : null}
{props?.top ? 'top ' : null}
{props?.bottom ? 'bottom ' : null}
{props?.max ? 'max ' : null}
"
>
<h5 if={ props?.title }>{ props?.title }</h5>
<div>
{ props?.message }
<slot name="body"></slot>
</div>
<nav class="right-align no-space">
<button onclick={ (ev) => clicked(ev, "cancel") } class="transparent link" if={ !props?.disableCancel }>{ props?.cancelText ?? "cancel" }</button>
<button onclick={ (ev) => clicked(ev, "confirm") } class="transparent link" if={ !props?.disableConfirm }>{ props?.confirmText ?? "confirm" }</button>
<slot name="button"></slot>
</nav>
</dialog>
<script>
export default {
clicked (e, name) {
e.preventDefault();
e.stopPropagation();
this.root.dispatchEvent(new Event(name));
}
}
</script>
</c-dialog>
Source Code: https://github.com/steevepay/riot-beercss/blob/main/components/c-dialog.riot
Let's break down the code:
- The
<c-dialog>
and</c-dialog>
define a custom root tag, with the same name as the file. You must write it; otherwise, it may create unexpected results. Using the<dialog></dialog>
as a root tag or redefining native HTML tags is a bad practice, so startingc-
is a good naming. - The Dialog has three main sections:
-
A title as header filled thanks to the
{props.title}
. -
A message as body printed with
{props.message}
. - A call to action with two buttons: cancel and confirm.
-
A title as header filled thanks to the
- When a button is clicked, the
click
Event is caught into the clicked function, and then a Custom Event is emitted to the parent HTML withthis.root.dispatchEvent(new Event(name));
: it will emit eitherconfirm
orcancel
. - The modal is displayed only if the props.active exists and is positive; then, the class
active
is applied. - The Dialog component has different styles, and it is printed conditionally if their corresponding
props
exist, for making the Dialog fullscreen:{props?.max ? 'max ' : null}
: if the propertymax
exists, the class max is applied.
Finally, load and instantiate the c-dialog.riot in a front page named index.riot:
<index-riot>
<div style="width:800px;padding:20px;">
<c-button onclick={ (ev) => update({ active: !state.active, max: false })}>Dialog</c-button>
<c-button onclick={ (ev) => update({ active: !state.active, max: true })}>Max</c-button>
<c-dialog
title="Dialog"
message="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
active={ state.active }
oncancel={ cancel }
onconfirm={ confirm }
max={ state.max }
/>
</div>
<script>
import cButton from "../components/c-button.riot"
import cDialog from "../components/c-dialog.riot"
export default {
components: {
cDialog,
cButton
},
state: {
active: false,
left: false,
max: false
},
cancel() {
console.log("dialog cancel")
this.update({ active: false })
},
confirm() {
console.log("dialog confirm")
this.update({ active: false })
}
}
</script>
</index-riot>
Source Code: https://github.com/steevepay/riot-beercss/blob/main/examples/index.dialog.riot
Code details:
- Components are imported with
import cDialog from "./components/c-dialog.riot";
then loaded in the components:{} Riot object. - The
dialog
component is instantiated with<c-dialog/>
on the HTML. - The state of the Dialog is stored in the state:{} Riot object under the
state.active
Boolean property. The property is passed as an attribute, such as:<c-dialog active={ state.active }/>
. When the button clicks, it sets the active property totrue
and displays the modal. - The dialog's title and message are passed as attributes.
- If the cancel or confirm button is clicked, it will emit two custom events:
-
oncancel: it will execute the
this.cancel()
function, and close the modal. -
onconfirm: it will execute the
this.confirm()
function, and close the modal.
-
oncancel: it will execute the
- Both calls to action can be bound to a custom function: make an API call, add an HTML element, send an email, confirm a deletion and more!
Dialog Component Testing
It exists two methods for testing the Dialog component, and it is covered in two different articles:
Conclusion
Voilà 🎉 We made a Dialog Riot Component using Material Design elements with BeerCSS.
The source code of the modal is available on Github:
https://github.com/steevepay/riot-beercss/blob/main/components/c-dialog.riot
Have a great day! Cheers 🍻