Welcome to my blog series on Riot. My colleague, Brady Cartmell, and I will be co-authoring this series. We recently used Riot on two major production projects, and we loved it. It even exceeded our expectations and gave us some pleasant surprises on several occasions. We are very happy with it, and are excited to share with the community our experience using it. We think it’s a great choice for writing web UI in the year 2016 and forward. We believe it’s worth your time to consider using it in your web projects too.
- What is Riot and why it’s great.
- Creating a small reusable component in Riot.
- Useful patterns in Riot.
- Caveats and lessons learned about Riot.
What is Riot?
To quote from Riot home page: Riot is a React-like UI micro-library. It offers custom tags, enjoyable syntax, virtual DOM and is tiny in size.
Riot combines the component-driven architecture pioneered by React with a pleasant syntax that is both familiar and similar to the emerging Web Components standards. Riot maintains a separation of concerns by keeping components isolated while unifying HTML, CSS, and JavaScript.
To get an idea of what a Riot tag looks like, let’s look at the example tag definition provided on Riot’s home page:
<todo>
<!-- layout -->
<h3>{ opts.title }</h3>
<ul>
<li each={ item, i in items }>{ item }</li>
</ul>
<form onsubmit={ add }>
<input>
<button>Add #{ items.length + 1 }</button>
</form>
<!-- style -->
<style scoped>
h3 {
font-size: 14px;
}
</style>
<!-- logic -->
<script>
this.items = []
add(e) {
var input = e.target[0]
this.items.push(input.value)
input.value = ''
}
</script>
</todo>
The usage of this tag would look like this: <todo title=”Things to do”></todo>
Check out Riot website. It’s a quick read. I think they do a very good job of explaining their rationale behind Riot. I agree with them that Riot seems to offer the right balance for a UI library. It’s not too big, not too small. It feels just right.
Disclaimer: this blog post series is NOT about comparing Riot with React or any other libraries. Other libraries are mentioned as needed for the sake of making a point. In the future we might write some blog posts specifically for the purpose of comparing Riot with other libraries should the need arise.
Why is Riot great?
Here is a run-down of some of Riots great features, all provided in just 9.35KB.
UI component encapsulation
It allows us to build truly encapsulated web components, now. We believe UI components is the way of the future. UI Components are self-contained, each with its own layout, logic, and styles. Data is passed into components via HTML attributes, making them easily testable, easy to reason about, and predictable.
We want to separate the concerns (UI from business logic), but we want to keep the UI technologies (HTML, CSS, JavaScript) together. It’s a beautiful thing to be able to write HTML, CSS and JS all in the same file and have them work together for the same UI component.
Reusability
Once you’ve defined a Riot tag (the official name of a custom component), you can use it in your HTML just as you would use a a native element like a <div> or <p>.
From a development perspective, all we need to do to reuse a component in another project is to copy and paste the file in which the component is defined! That’s it. We don’t have to worry about if it contains the right HTML, CSS or JavsScript, or if we need to dig for them somewhere else. Better yet, we could put all of our shared components files into a common code repository and just reference that repository in different projects. That way when a component’s source is updated, that component is updated in every project that references it. Granted, this will require some initial project setup and may not be the desired behavior in every project. But either way, this is certainly a lot more reusable than having your UI code for the same component scattered across different files.
Simple and easy to read
Once you get used to the one way data flow concept, you can pretty much write your UI code in Riot with standard HTML, CSS and JS like you always have with very minimal new syntax.
Small API surface
To continue on the topic of simplicity, Riot has a very small API surface and learning curve compared to React. It does, however, provide some useful patterns and methods such as an event system for tag life cycle, mixins for common functions, observables for custom events, and flow control HTML attributes (if and each). You really don’t need to know too much more to start writing a Riot component.
Virtual DOM
If you are familiar with React, then you know exactly what a virtual DOM is. It’s basically a proprietary representation of the DOM in memory. Riot includes a light weight virtual DOM that can automatically diff against the browser’s DOM and determine the minimum set of modifications to update the UI when any part of your app’s state is modified in response to an event.
Virtual DOM does one way data flow, which means updates and unmounts are propagated downwards from parent to children. We prefer one way data flow b/c it makes it easier to reason about your app’s behavior, esp. when the UI logic becomes complex.
Scoped CSS
The Scoped attribute and pseudo class is implemented by Riot. You can use it like this
<todo>
<!-- layout -->
<h3>{ opts.title }</h3>
<style scoped>
:scope { display: block }
h3 { font-size: 120% }
/** other tag specific styles **/
</style>
</todo>
Adding the ‘scoped’ attribute to the <style> of your custom tag will automatically ensure that all the CSS defined within is scoped to the tag. This allows you to freely style your tag without needing to think about specificity or side-effects. For those of us who have been writing CSS for large web projects for a while, OMG! This is so nice!
Another great “side effect” of this is that it dramatically reduces the cognitive load on your brain when trying to be creative with naming your CSS classes. (We all know naming is hard!) Such a relief! Plus it also saves a lot of typing.
CSS injection and overriding
All the component styles are injected into one place, the <head> section, and many instances of the same component share just ONE copy of the component’s styles.
To make it easier to override component styles, we can specify where in the <head> section Riot should inject component styles:
<style type="riot"></style>
Plays nicely with others
Riot is unopinionated in regards to your choice of CSS and JS preprocessors, as well as your choice of front-end build managers. Just point it to your preprocessors of choice and it will automatically use them as part of its compile process.
We used LESS for CSS preprocessing. All we had to do to make Riot work with LESS was to add “type=’less'” to the “styles” section in each tag, like this <style scoped type=”less”></style>.
According to their docs, Riot works well with ES6, TypeScript, CoffeeScript, NPM, CommonJS, AMD, Bower, Gulp, Grunt, etc. We used JSPM for our front end build process and ES6 for coding. Riot worked very well with them, granted it took us some time initially to get things set up. But that’s mostly b/c we were new to JSPM too. Perhaps in the future we can write a separate blog post on setting up the front end dev environment and build process with JSPM, Riot, ES6, LESS, etc. BTW, we love JSPM. It’s awesome!
The biggest thing we liked and used a lot is the arrow functions in ES6 in conjunction with Riot. We used it to define methods on the component instance and the arrow function preserves the “this” context automatically, which points to our component instance. This came in very handy as we always knew that the “this” keyword was referring to the current tag instance.
Forward thinking with Web Components
The Web Components standards are actively being worked on right now by W3C and browser vendors. We believe it will become the standard way of writing web UI in a couple of years. Riot’s syntax and structure are similar to Web Components. It allows you to write web UI today in a way that Web Components will when it is fully implemented.
There are a couple of obvious benefits to this. For one, Riot “forces” you to properly write a web component and thus preparing you for the future. For two, your Riot code will be more ready to be ported over to Web Components when you are ready.
According to Riot team, they see Riot as an abstraction over Web Components standard just like jQuery is an abstraction over the DOM today. When the day comes when Web Components is ready for prime time, Riot can serve as a simpler abstraction layer on top of Web Components and we can get the best of both worlds.
Easy access to named elements
Inside a Riot component, any Html element with a “name” or “id” attribute automatically gets bound to the component context as a property on “this”. It makes it so much easier to reference html elements inside a component. For eg,
<login>
<form id="login" onsubmit={ submit }>
<input name="username">
<input name="password">
<button name="submit">
</form>
// grab above HTML elements
var form = this.login,
username = this.username.value,
password = this.password.value,
button = this.submit
</login>
Nested Html with <yield />
The special <yield /> tag allows you to include nested content when you use one of your custom tags. Just like you would include content in a <div> or <p>:
<custom-tag>
…inner html for custom-tag…
</custom-tag>
Conclusion
In summary, we feel like Riot has hit a sweet spot when it comes to picking a foundation to build your UIs on top of. It’s taken the best of all that’s out there in the jungle of web development and has put them into a nice little library that offers just the right number of features. It’s a shame that Riot is not as popular as it is. Hopefully this blog series can help change that.
In the next post of this series, we’ll dig into creating a non-trivial Riot tag. Then we’ll take a look at some useful patterns to get used to when working with Riot. Finally, we’ll talk about some caveats to be aware of and some lessons learned while using Riot for real-world apps.