What is Riot?

Riot brings custom tags to all browsers. Think React + Polymer but with enjoyable syntax and a small learning curve.

Why do we need a new UI library?

The frontend space is indeed crowded, but we honestly feel the solution is still “out there”. We believe Riot.js offers the right balance for solving the great puzzle.

So — here’s why we need one:

Custom elements

Riot.js brings custom elements to all modern browsers without the use of any polyfill!

  <!-- layout -->
  <h1>{ props.title }</h1>

    <li each={ item in state.items }>{ item }</li>

  <form onsubmit={ add }>
    <input name="todo">
    <button>Add #{ state.items.length + 1 }</button>

  <!-- style -->
    :host {
      padding: 16px;

  <!-- logic -->
    export default {
      state: {
        items: []
      add(e) {
        const input =


        input.value = ''

A custom element glues relevant HTML and JavaScript together forming a reusable component. It is designed to offer you everything you wished native the web components API looked like.


Custom tags let you build complex views with HTML. Your application might look something like this:

  <h1>Riot.js application</h1>

  <my-header class="js-component"/>

    <my-articles class="js-component"/>
    <my-sidebar class="js-component"/>

  <my-footer class="js-component"/>

    riot.mount('.js-component', { store: createApplicationStore() })

HTML syntax is the de facto language of the web and it’s designed for building user interfaces. The syntax is explicit, nesting is inherent to the language, and attributes offer a clean way to provide options for custom tags.

Riot.js tags are compiled to Pure JavaScript before browsers can execute them.

Performant and predictable

  • Absolutely the smallest possible amount of DOM updates and reflows.
  • Fast expressions bindings instead of virtual DOM memory performance issues and drawbacks.
  • One way data flow: updates and unmounts are propagated downwards from parent to children
  • Expressions are pre-compiled and cached for high performance
  • Lifecycle events for more control
  • Server-side rendering of custom tags for universal (isomorphic) applications

Close to standards

  • Future proof thanks to the JavaScript module syntax.
  • The rendered DOM can be freely manipulated with other tools
  • Web Components like API
  • No need for external polyfills or additional libraries
  • No proprietary event system
  • No extra HTML root elements, data-attributes or fancy custom attributes.

Tooling friendly

  • Create components with CoffeeScript, Jade, LiveScript, TypeScript, ES6 or any pre-processor you want.
  • Build with @riotjs/cli, Webpack, Rollup, Parcel, Browserify.
  • Test with whatever you like, you can load your Riot tags directly in node

Simple and minimalistic

Minimalism sets Riot.js apart from others:

1. Enjoyable syntax

One of the design goals was to introduce a powerful tag syntax with as little boilerplate as possible:

  • No extra brain load for attributes like className, htmlFor
  • Shortcut spread operator for multiple attributes: <p { ...attributes }></p>
  • Expressions Interpolation: Add #{ items.length + 1 } or class="item { activeClass }"
  • export default statement to define the tag’s public interfaces
  • No side effects due to asynchronous rendering or Proxy objects
  • Functional API over OOP class-based syntax
  • Automatic CSS styling via <style> tag without shadow DOM hassle

2. Small learning curve

Riot.js has between 10 and 100 times fewer API methods than other UI libraries.

  • Less to learn. Fewer books and tutorials to view
  • Only 3 template directives to learn if, each and is
  • Less proprietary stuff
  • No new syntax to learn
  • No “magic” or “smart” reactive properties or hooks
  • Explicit behaviors over implicit assumptions

3. Tiny size

  • Polymer – 89.62KB (gzip)

  • Angular – 56.73KB (gzip)

  • React – 43.0KB (gzip)

  • Vue – 23.46KB (gzip)

  • Riot – 7.13KB (gzip)

  • Preact – 3.87KB (gzip)

  • Only 7kb!

  • Fewer bugs

  • Faster to parse and cheaper to download

  • Embeddable. The library ought to be smaller than the application

  • Less to maintain. We don’t need a big team to maintain Riot

4. Small, but complete

Riot.js has all the essential building blocks for modern client-side applications:

  • Modular views for building user interfaces
  • High performance with many DOM nodes
  • Highly extensible and not opinionated

Riot.js is an “open stack”. It’s meant for developers who want to avoid framework-specific idioms. The generic tools let you mix and match design patterns you prefer most.
Powerful and modular ecosystem

The Riot.js ecosystem is completely modular. It’s designed to let you pick only the stuff you really need:

  • @riotjs/cliCLI to compile locally your tags to JavaScript
  • @riotjs/ssr – Super simple server side rendering
  • @riotjs/hydrate – Hydration strategy for your SPA
  • @riotjs/route – Isomorphic router
  • @riotjs/lazy – Lazy components loader
  • @riotjs/hot-reload – Live reload plugin
  • @riotjs/compiler – Advanced tags compiler
  • @riotjs/parserHTML parser
  • @riotjs/dom-bindings – Expressions based template engine
  • @riotjs/now – now integration
  • @riotjs/custom-elements – native custom elements implementation


Riot.js is Web Components for everyone. Think React + Polymer but without the bloat. Its API is heavily inspired by Vue.js but it contains just the bare minimum to build a modern frontend project. It’s intuitive to use and it weighs almost nothing. And it works today. No reinventing the wheel, but rather taking the good parts of what’s there and making the simplest tool possible.

The Riot.js design was driven by The Zen of Python, by Tim Peters philosophy, that’s our mantra:

Beautiful is better than ugly.

Explicit is better than implicit.

Simple is better than complex.

Complex is better than complicated.

Flat is better than nested.

Sparse is better than dense.

Readability counts.

Special cases aren’t special enough to break the rules.

Although practicality beats purity.

Errors should never pass silently.

Unless explicitly silenced.

In the face of ambiguity, refuse the temptation to guess.

There should be one– and preferably only one –obvious way to do it.

Although that way may not be obvious at first unless you’re Dutch.

Now is better than never.

Although never is often better than right now.

If the implementation is hard to explain, it’s a bad idea.

If the implementation is easy to explain, it may be a good idea.

Namespaces are one honking great idea – let’s do more of those!