Getting Started with Riot.js
May 2nd, 2017 | By Lamin Sanneh | 9 min read
[Javascript fatigue](/javascript-scene/why-im-thankful-for-js-fatigue-i-know-you-re-sick-of-those-words-but-this-is-different-296fae0c888f#.3vrc90qtj "target="_blank) is still an ongoing thing. Even before introducing our new framework, there seems to be an acknowledgment of the above.
Even with this acknowledgment, one should always keep tabs on what’s new even if it’s not used immediately. A couple of reasons why. You might find it a good fit for a future project. Secondly, you may learn a better paradigm of programming in what’s new, sometimes even without switching to the new framework, you may still be able to incorporate it into the one you’re currently using, as a framework user or developer.
Regardless of the number of libraries out there, it is vital to give room for newcomers. This is because there is always a chance for improvement or otherwise. I say otherwise due to other frameworks such as Ember.js that cater and promote the idea that "more is better". I have discovered a library that says otherwise.
Let’s say you need something structured as in React.js or Ember.js, but only need to integrate it into an existing application in a very minimal way. Something you can just drop in and get going. Here, I introduce you Riot.js.
Before we proceed, if you are curious, you can see a link to a demo here, and you can also download the repository here.
Riot.js, such as React.js, uses a self-contained single file component. However, Riot.js takes this to the next level because you do not need to import a component to use it inside of another. The [Riot.js website](/ "target="_blank) acknowledges the brilliance of React.js, yet they believe they are addressing some of the library’s weak points.
The most appealing thing to me about Riot.js is how easy it is to drop it into an existing application. We can link to our Riot.js components, instantiate the main one, pass it some JSON data, and have it be part of our program. All of this without sacrificing things we’ve grown to love with Angular.js and React.js, such as code manageability with components, familiar APIs, for example, looping over data, templating, handling DOM events such as clicks, and easy component nesting.
So now that we have been introduced to Riot.js, let's describe the application we’ll be building. We will build a tab of contents application called tabs. It can potentially be used as a categorized list of links or categories of anything. We will use a static array of data but as you’ll see, this data could come from some JSON call and is easily switchable.
To get started, Riot.js comes with a command line interface. However, it is not necessary as Riot.js has an in-browser compiler which you can include as a script. In fact, we will build the tabs application without using the CLI. For production or larger applications, it may be worth looking into. The CLI makes it easy to include a large number of component files as you do not have to include them individually as we will do in this article. However, for small projects like ours, manual inclusion is fine. We will touch on its usage in the last part of this article. To get it out of the way you can install it using the below npm command:
npm install riot - g
Now let’s start writing our application.
Create a html file called index.html, and add in the boilerplate below:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Tabs</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div class="main-container">
</div>
<script type="text/javascript">
var tabs = [{
id: 1,
title: "tab 1",
content: "some content 1"
},
{
id: 2,
title: "tab 2",
content: "some content 2"
},
{
id: 3,
title: "tab 3",
content: "some content 3"
}
];
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/riot/3.3.0/riot+compiler.min.js"></script>
</body>
</html>
In this boilerplate, we are linking to the Riot.js CDN link which contains the main library, and the in-browser compiler. This removes the need for a command line compiler. We are also creating an array, which is a list of objects, each representing a tab and its content.
Next, in the head of the document, add the styles below for our tabs:
<style>
.tab-content {
display: none;
}
.tab-headers {
display: flex;
}
.tab-header {
background-color: #eff0f2;
color: #888;
padding: 5px 10px;
border-bottom: 2px solid #87d3b7;
}
.tab-header:hover {
cursor: pointer;
}
.tab-header.active {
background-color: #87d3b7;
color: #FFF;
}
.tab-content {
padding: 5px;
}
.tab-content.active {
display: block;
}
</style>
After the inclusion of the Riot.js library, add in this line:
<script>
riot.mount('*', {
tabs: tabs,
defaultTabIndex: 1
})
</script>
This bootstraps our application and passes in an optional object as the application data and options. The options and data are pure javascript data types. Here, we are passing in the list of tabs we created moments ago. We are also passing in the index of the currently visible tab by default.
Let’s create our main Riot.js component. Create a file within a components directory called components/tabs.tag.
The file extension .tag is not a compulsory one to use but it is a common convention used in the Riot.js documentation. In this file put in the following:
<tabs>
<tab-headers isclicked={this.isclicked} tabs="{opts.tabs}"></tab-headers>
<tab-contents tabs="{opts.tabs}"></tab-contents>
<script>
this.on('before-mount', function() {
if (typeof opts.defaultTabIndex !== "undefined") {
opts.tabs[opts.defaultTabIndex].active = true;
}
})
this.isclicked = (event) => {
opts.tabs.forEach((tab) => {
if (event.item.tab.id == tab.id) {
tab.active = true;
} else {
tab.active = false;
}
});
this.update();
}
</script>
</tabs>
This is how a Riot.js component file is created.
First, we wrap the whole of the component using the custom tags as we intend to use them in our application, in this case:
<tabs>
</tabs>
Inside of the custom tag, we have the contents of the component which can be static HTML content or inclusion of other components as we have above. Those components have not been created yet but we will do so in a moment.
Finally, you have an optional scripts tag which is where the logic of the component will live. In our component above, we have an event handler we want to run before the component is inserted into the DOM.
Riot.js has several of these lifecycle events.
We also have a function we want to use as part of the component. This is used to handle the click event on a tab heading but we will get to that shortly.
Now that we have the basic foundation of a component, let’s create the other components.
The main component will include as contents, the list of tab headers, and a list of tab contents. When we click on a tab header, the corresponding content tab will be visible and the others will be hidden.
Create the tab-headers component components/tab-headers.tag with the contents:
<tab-headers>
<div class="tab-headers">
<tab-header onclick="{parent.opts.isclicked}" each={tab in opts.tabs} tab="{tab}"></tab-header>
</div>
</tab-headers>
And the create the component components/tab-header with the component:
<tab-header>
<div class="{active: opts.tab.active} tab-header">{opts.tab.title}</div>
</tab-header>
In the tab-headers component, we are looping over the list of tabs which was passed in when we mounted the components in index.html.
In each loop instance, we are creating a tab-header component instance and passing in event handlers and values. The list of tabs is accessible through a special property called opts which is available in all components. The property lets you access properties passed in by a parent component.
In Riot.js, you can pass in values and functions as data properties as we are doing in tab-headers. We are passing in a click handler from the top level parent tabs component onto each child tab-header component. A component can access the parent properties and functions of a component using the property called parent. Remember there is a distinction between parent properties and passed in properties. To access a passed in property you can directly go through that component’s opt property. However, to access a parent’s property, you must go through the parent property of the component.
In the tab-header component, we are displaying the tab title as the title of the tab. We are also adding or removing the class active depending on whether the tab is active or not.
Now that we have created the tabs, tab-headers, and tab-header components, let’s add them into our main html page. Before the mount statement, add the following lines to include the components:
<script src="components/tab-header.tag" type="riot/tag"></script>
<script src="components/tab-headers.tag" type="riot/tag"></script>
<script src="components/tabs.tag" type="riot/tag"></script>
Finally, let’s create the components for the tab contents.
Create a component in components/tab-contents with the content:
<tab-contents>
<div class="tab-contents">
<tab-content each={tab in opts.tabs} tab="{tab}"></tab-content>
</div>
</tab-contents>
Create components/tab-content with the content:
<tab-content>
<div class="{active: opts.tab.active} tab-content">{opts.tab.content}</div>
</tab-content>
Link to the component file by using:
<script src="components/tab-content.tag" type="riot/tag"></script>
<script src="components/tab-contents.tag" type="riot/tag"></script>
Now our application has been created but we still need to use the main component to make it appear. In index.html, inside of the main-container div put:
<tabs></tabs>
Let's revisit the isclicked function in the main component:
<script>
// Some code here
...
this.isclicked = (event) => {
opts.tabs.forEach((tab) => {
if (event.item.tab.id == tab.id) {
tab.active = true;
} else {
tab.active = false;
}
});
this.update();
}
</script>
What we are doing in here is setting which tab in the list is active when a header is clicked. We achieve this is by setting a click event handler on the tab-header. When clicked, this function is called:
<tab-header onclick="{parent.opts.isclicked}" each={tab in opts.tabs} tab="{tab}"></tab-header>
Now point a web server to the root directory which contains the index.html file.
Open the web server URL in a browser and now, we should have a functional tabs application.
So now the application is functional but let’s revisit the riot compiler we mentioned earlier. Currently, we are manually linking to components. This is fine for our simple application but it could become tedious if we have tens or even hundreds of components to link to. Let's combine all the components into one file.
We will compile and concatenate all the component files into one file called app.js which is the only file we will link to.
On the command line, navigate to the project root folder and run the command:
riot components app.js
This will run the compiler just once. To have a watcher on the components folder that’ll run the compiler automatically when the contents change, run the following instead:
riot components app.js - w
Link to the newly created file by removing all the links to the individual component files, and adding the following just before we mount the components:
<script src=“app.js”></script>
Riot.js takes many of the good parts of React.js and makes it even simpler. There are many tools available to use Riot.js but as you have seen above, they are just complementary to Riot.js but are not absolutely necessary to get a functional application up and running.
Have you used Riot.js before or are considering it for your next project?
Jscrambler
The leader in client-side Web security. With Jscrambler, JavaScript applications become self-defensive and capable of detecting and blocking client-side attacks like Magecart.
View All Articles