API · Custom tags

Mounting

riot.mount(customTagSelector, [opts])

customTagSelector selects elements from the page and mounts them with a custom tag. The selected elements’ name must match the custom tag name.

opts optional object is passed for the tags to consume. This can be anything, ranging from a simple object to a full application API. Or it can be a Flux- store. Really depends on how you want to structure your client-side applications. Read more about modular Riot applications. Also note that attributes you set on your tags as options will take precedence over ones specified with same names via opts argument.

// selects and mounts all <pricing> tags on the page
var tags = riot.mount('pricing')

// mount all custom tags with a class name .customer
var tags = riot.mount('.customer')

// mount <account> tag and pass an API object as options
var tags = riot.mount('account', api)

@returns: an array of the mounted tag instances

Note: users of In-browser compilation will need to wrap calls to riot.mount in riot.compile in order to get returned tag instances. Without this, calls to riot.mount will return undefined.

riot.compile(function() {
  // here tags are compiled and riot.mount works synchronously
  var tags = riot.mount('*')
})

riot.mount(‘*’, [opts])

A special Riot specific selector “*” can be used to mount all custom tags on the page:

riot.mount('*')

@returns: an array of the mounted tag instances

riot.mount(selector, tagName, [opts])

Where

// mounts custom tag "my-tag" to div#main and pass api as options
var tags = riot.mount('div#main', 'my-tag', api)

@returns: an array of the mounted tag instances

riot.mount(domNode, tagName, [opts])

Mount a custom tag named tagName on a given domNode passing optional data with opts. For example:

// mounts "users" tag to #slide node and pass api as options
riot.mount(document.getElementById('slide'), 'users', api)

@returns: an array of the mounted tag instances

riot.unregister(tagName)

Unregistering a tag previously created via compiler or via riot.tag() This method could be handy in case you need to test your app and you want to create multiple tags using the same name for example

// create a test tag
riot.tag('test-tag', '<p>{ message }</p>')

// mount it
var tag = riot.mount(document.createElement('div'), 'test-tag')[0]
expect(tag.root.querySelector('p')).to.be.ok

// unregister the tag
riot.unregister('test-tag')

// recreate the same tag using a different template
riot.tag('test-tag', '<div>{ message }</div>')

Rendering

riot.render(tagName, [opts])

Rendering a tag to html.
Only available on server-side. For example:

// render "my-tag" to html
var mytag = require('my-tag')
riot.render(mytag, { foo: 'bar' })

@returns: tags render as html

riot.require(tagPath, [opts])

Requiring and compiling riot tags in runtime
Only available on server-side.
It works like require('./my-tag.tag') but it gives you the possibility to compile your tags using any of the given riot-compiler options. For example you can require and use a preprocessor at same time.

var tag = riot.require('./my-tag.jade', { template: 'jade' })

@returns: the tag name

riot.renderAsync(tagName, [opts])

Rendering asynchronously a tag to html.
Only available on server-side.
This method returns a promise that will be resolved only when a “ready” event will be triggered by your tags during the mounting process. For example:

On the server:

riot.renderAsync(tagName, opts)
  .then(function(html) {
    // do something with your html
  })
  .catch(function(e) {
    // it took too much time!
  })

In your tag:

<async-rendering>
  <p>{ message }</p>

  this.message = 'hi'

  setTimeout(function() {
    // triggering the "ready" event will resolve the promise
    this.trigger('ready')
  }.bind(this), 500)

</async-rendering>

It’s important to notice that if the “ready” event will not be triggered, the promise will be rejected after 1 second. You can configure the internal riot promises timeout via riot.settings.asyncRenderTimeout (default 1000ms)

@returns: Promise

Tag instance

Following properties are set for each tag instance:

You can use these references in both the HTML and JavaScript code. For example:

<my-tag>
  <h3>{ opts.title }</h3>

  var title = opts.title
</my-tag>

You can freely set any data to the instance (aka “context”) and they are available in the HTML expressions. For example:

<my-tag>
  <h3>{ title }</h3>

  this.title = opts.title
</my-tag>

Note: if you have some globals, you can also use these references in both the HTML and JavaScript code:

window.someGlobalVariable = 'Hello!'
<my-tag>
  <h3>{ someGlobalVariable }</h3>

  var message = someGlobalVariable
</my-tag>

Updating

this.update()

Updates all the expressions on the current tag instance as well as on all the children. This method is automatically called every time an event handler is called when user interacts with the application.

You can skip the riot automatic updates by setting the preventUpdate = true property to your event object for example:

<my-tag>
  <button onclick={ click }>{ message }</button>

  <script>
    this.message = 'hi'

    click(e) {
      e.preventUpdate = true // your tag will not update automatically
      this.message = 'goodbye'
    }
  </script>
</my-tag>

Other than that riot does not update the UI automatically so you need to call this method manually. This typically happens after some non-UI related event: after setTimeout, AJAX call or on some server event. For example:

<my-tag>

  <input name="username" onblur={ validate }>
  <span class="tooltip" show={ error }>{ error }</span>

  <script>
    validate() {
      $.get('/validate/username/' + this.username.value)
        .fail(function(error_message) {
          this.error = error_message
          this.update()
        }.bind(this))
    }
  </script>
</my-tag>

On above example the error message is displayed on the UI after the update() method has been called. We assign this variable to self since inside the AJAX callback this variable points to the response object and not to the tag instance.

If you want to have more control over your tags DOM updates you can set a custom shouldUpdate function, and your tag will update only if that function will return true

<my-tag>
  <button onclick={ click }>{ message }</button>

  <script>
    this.message = 'hi'

    click(e) {
      this.message = 'goodbye'
    }
    // data here is what you have passed to your update method
    // in case of this.update() it will be undefined
    shouldUpdate(data, nextOpts) {
      // do not update
      if (this.message === 'goodbye') return false
      // if this.message is different from 'goodbye' we could update the tag
      return true
    }
  </script>
</my-tag>

The shouldUpdate method will always receive 2 arguments: the first one contains the values you want to update via the tag.update method and the second argument will be the new options received via tag attributes and normally stored in the opts object.

<my-tag>
  <child-tag message={ message }></child-tag>
  <button onclick={ click }>Say goodbye</button>

  <script>
    this.message = 'hi'

    click(e) {
      this.message = 'goodbye'
    }
  </script>
</my-tag>

<child-tag>
  <p>{ opts.message }</p>

  <script>
    shouldUpdate(data, nextOpts) {
      // update the DOM depending on the new options received
      return nextOpts.message !== 'goodbye'
    }
  </script>
</child-tag>

this.update(data)

Set values of the current instance and update the expressions. This is same as this.update() but allows you to set context data at the same time. So instead of this:

self.error = error_message
self.update()

you can do this:

self.update({ error: error_message })

which is shorter and cleaner.

riot.update()

Updates all the mounted tags and their expressions on the page.

@returns: an array of tag instances that are mounted on the page.

Unmounting

this.unmount(keepTheParent)

Detaches the tag and its children from the page. An “unmount” event is fired. If you want to unmount a tag without removing the parent tag you need to pass true to the unmount method

Remove the tag from the DOM:

mytag.unmount()

Remove the tag children and keep only the parent tag:

mytag.unmount(true)

Nested tags

You have access to nested tag instances via tags variable:

<my-tag>

  <child></child>

  // access to child tag
  var child = this.tags.child

</my-tag>

If more than one of the same child tag is used, it is accessed as an array this.tags.child[n]

You can also use the ref attribute to give another name for the nested tag.

<my-tag>

  <child ref="my_nested_tag"></child>

  // access to child tag
  var child = this.refs.my_nested_tag

</my-tag>

The child tags are initialized after the parent tag so the methods and properties are available on the “mount” event.

<my-tag>

  <child ref="my_nested_tag"></child>

  <script>
    // access to child tag methods
    this.on('mount', function() {
      this.refs.my_nested_tag.someMethod()
      // this.tags.child.someMethod() is also valid
    })
  </script>
</my-tag>

Yielding nested HTML

The <yield> tag is a special riot core feature that allows you to inject and compile the content of any custom tag inside its template in runtime This technique allows you to extend your tags templates with html contents rendered eventually from the server

For example using the following riot tag my-post

<my-post>
  <h1>{ opts.title }</h1>
  <yield/>

  <script>
    this.id = 666
  </script>
</my-post>

anytime you will include the <my-post> tag in your app

<my-post title="What a great title">
  <p id="my-content-{ id }">My beautiful post is just awesome</p>
</my-post>

once mounted riot.mount('my-post') it will be rendered in this way:

<my-post>
  <h1>What a great title</h1>
  <p id="my-content-666">My beautiful post is just awesome</p>
</my-post>

Multi-Transclusion

>=2.3.12

The <yield> tag also provides a slot mechanism that allows you to inject html contents on specific slots in the template

For example using the following riot tag my-other-post

<my-other-post>
  <article>
    <h1>{ opts.title }</h1>
    <h2><yield from="summary"/></h2>
    <div>
      <yield from="content"/>
    </div>
  </article>
</my-other-post>

anytime you will include the <my-other-post> tag in your app

<my-other-post title="What a great title">
  <yield to="summary">
    My beautiful post is just awesome
  </yield>
  <yield to="content">
    <p>And the next paragraph describes just how awesome it is</p>
    <p>Very</p>
  </yield>
</my-other-post>

once mounted riot.mount('my-other-post') it will be rendered in this way:

<my-other-post>
  <article>
    <h1>What a great title</h1>
    <h2>My beautiful post is just awesome</h2>
    <div>
      <p>And the next paragraph describes just how awesome it is</p>
      <p>Very</p>
    </div>
  </article>
</my-other-post>

Yield and loops

The <yield> tag could be used also in a loop or in a child tag but you should be aware that it will be always parsed and compiled using the child data

The following blog.tag riot component

<blog>
  <h1>{ title }</h1>
  <my-post each={ posts }>
    <a href={ this.parent.backToHome }>Back to home</a>
    <div onclick={ this.parent.deleteAllPosts }>Delete all the posts</div>
  </my-post>

  <script>
    this.backToHome = '/homepage'
    this.title = 'my blog title'

    this.posts = [
      { title: "post 1", description: 'my post description' },
      { title: "post 2", description: 'my post description' }
    ]

    // the bind is needed in this case to keep the parent context
    // also in the child tags
    deleteAllPosts() {
      this.posts = []

      // we need to trigger manually the update function
      // because this function gets triggered from a child tag
      // and it does not bubble up automatically
      this.update()
    }
  </script>
</blog>

<my-post>
  <h2>{ title }</h2>
  <p>{ description }</p>
  <yield/>
</my-post>

will be compiled in this way:

<blog>
  <h1>my blog title</h1>
  <my-post>
    <h2>post 1</h2>
    <p>my post description</p>
    <a href="/homepage">Back to home</a>
    <div>Delete all the posts</div>
  </my-post>
  <my-post>
    <h2>post 2</h2>
    <p>my post description</p>
    <a href="/homepage">Back to home</a>
    <div>Delete all the posts</div>
  </my-post>
</blog>

Mixins

this.mixin(mixinObject)

Extends the current tag with functionality available on mixinObject. For example:

var OptsMixin = {
  // init method is a special one which can initialize
  // the mixin when it's loaded to the tag and is not
  // accessible from the tag its mixed in
  init: function() {
    this.on('updated', function() { console.log('Updated!') })
  },

  getOpts: function() {
    return this.opts
  },

  setOpts: function(opts, update) {
    this.opts = opts
    if (!update) this.update()
    return this
  }
}

<my-tag>
  <h1>{ opts.title }</h1>

  this.mixin(OptsMixin)
</my-tag>

riot.mixin(mixinName, mixinObject)

Register a shared mixin, globally available to be used in any tag: this.mixin(mixinName).

riot.mixin(mixinObject)

Register a global mixin, and automatically adds it to all tag instances.

Events

Each tag instance is an observable so you can use on and one methods to listen to the events that happen on the tag instance. Here’s the list of supported events:

For example:

// cleanup resources after tag is no longer part of DOM
this.on('unmount', function() {
  clearTimeout(timer)
})

Reserved words

The above method and property names are reserved words for Riot tags. Don’t use any of following as your instance variable or method name: opts, parent, tags, root, refs, update, unmount, on, off, one and trigger. Variables beginning with an underscore (e.g.: this._item) are reserved for internal use too. Local variables can be freely named. For example:

<my-tag>

  // allowed
  function update() { }

  // not allowed
  this.update = function() { }

  // not allowed
  update() {

  }

</my-tag>

Manual construction

riot.tag(tagName, html, [css], [attrs], [constructor])

Creates a new custom tag “manually” without the compiler.

Example

riot.tag('timer',
  '<p>Seconds Elapsed: { time }</p>',
  'timer { display: block; border: 2px }',
  'class="tic-toc"',
  function (opts) {
    var self = this
    this.time = opts.start || 0

    this.tick = function () {
      self.update({ time: ++self.time })
    }

    var timer = setInterval(this.tick, 1000)

    this.on('unmount', function () {
      clearInterval(timer)
    })

  })

See timer demo and riot.tag API docs for more details and limitations.

Warning by using riot.tag you cannot enjoy the advantages of the compiler and the following features are not supported:

  1. Self-closing tags
  2. Unquoted expressions. Write attr="{ val }" instead of attr={ val }
  3. Shorthand ES6 method signatures
  4. <img src={ src }> must be written as <img riot-src={ src }> in order to avoid illegal server requests
  5. <input value={ val }> must be written as <img riot-value={ val }> in order to avoid unexpected IE issues
  6. style="color: { color }" must be written as riot-style="color: { color }" so that style attribute expressions work in IE
  7. Scoped CSS precompilation.

You can take advantage of <template> or <script> tags as follows:

<script type="tmpl" id="my_tmpl">
  <h3>{ opts.hello }</h3>
  <p>And a paragraph</p>
</script>

<script>
riot.tag('tag-name', my_tmpl.innerHTML, function(opts) {

})
</script>

riot.Tag(el, [opts])

The riot.Tag constructor will allow you to create and extend your tags using es6 classes. If you want to create your riot tag you need to extend the riot.Tag constructor:

class MyTag extends riot.Tag {
  // mandatory in order to use and identify this component
  get name() {
    return 'my-tag'
  }
  get tmpl() {
    return `<p onclick="{ click }">{ message }, Dear user</p>`
  }
  get attrs() {
    return 'class="{ className }"'
  }
  get css() {
    return 'my-tag p{ color: blue; }'
  }
  onCreate(opts) {
    this.message = opts.message
  }
  click() {
    this.message = 'goodbye'
  }
}

new MyTag(
  document.getElementById('my-div'),
  { message: 'hi' }
).mount()

You can also combine your riot tags extending them starting from a common ancestor

class Logger extends riot.Tag {
  get name() {
    return 'logger'
  }
  get tmpl() {
    return `<div>{ opts.log }</div>`
  }
}

class ErrorLogger extends Logger {
  get name() {
    return 'error-logger'
  }
  get css() {
    return 'error-logger div { color: red; }'
  }
}

class SuccessLogger extends Logger {
  get name() {
    return 'success-logger'
  }
  get css() {
    return 'success-logger div { color: green; }'
  }
}

new ErrorLogger(
  document.querySelector('.error'),
  { log: 'oups!!!' }
).mount()

new SuccessLogger(
  document.querySelector('.success'),
  { log: 'well done!!!' }
).mount()