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
.
<script>
riot.compile(function() {
// here tags are compiled and riot.mount works synchronously
var tags = riot.mount('*')
})
</script>
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
-
selector
selects any DOM nodes from the page to be mounted -
tagName
specifies the custom tag name to be used -
opts
optional object is passed for the tags to consume
// 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
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.renderAsync(tagName, [opts])
>= v2.6.3
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:
-
opts
- the options object -
parent
- the parent tag if any -
root
- root DOM node -
tags
- nested custom tags
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.
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>
var self = this
validate() {
$.get('/validate/username/' + this.username.value)
.fail(function(error_message) {
self.error = error_message
self.update()
})
}
</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.
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 name
attribute to give another name for the nested tag.
<my-tag>
<child name="my_nested_tag"></child>
// access to child tag
var child = this.tags.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 name="my_nested_tag"></child>
// access to child tag methods
this.on('mount', function() {
this.tags.my_nested_tag.someMethod()
})
</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/>
this.id = 666
</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>
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()
}.bind(this)
</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:
- “update” – right before the tag is updated. allows recalculation of context data before the UI expressions are updated.
- “updated” – right after the tag is updated. allows do some work with updated DOM
- “before-mount” – right before tag is mounted on the page
- “mount” – right after tag is mounted on the page
- “before-unmount” – before the tag is removed from the page
- “unmount” – after the tag is removed from the page
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
, 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.
-
tagName
the tag name -
html
is the layout with expressions -
css
is the style for the tag (optional) -
attrs
string of attributes for the tag (optional). -
constructor
is the initialization function being called before the tag expressions are calculated and before the tag is mounted
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:
- Self-closing tags
- Unquoted expressions. Write
value="{ val }"
instead ofvalue={ val }
- Boolean attributes. Write
__checked="{ flag }"
instead ofchecked={ flag }
- Shorthand ES6 method signatures
-
<img src={ src }>
must be written as<img riot-src={ src }>
in order to avoid illegal server requests -
style="color: { color }"
must be written asriot-style="color: { color }"
so that style attribute expressions work in IE - 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(impl, conf, innerHTML)
experimental
In riot 2.3 we gave you the access to the internal Tag instance in order to let you create your custom tags in more creative ways.
-
impl
-
tmpl
tag template -
fn(opts)
the callback function called on the mount event -
attrs
root tag html attributes as object (key => value)
-
-
conf
-
root
DOM node where you will mount the tag template -
opts
tag options -
isLoop
is it used in as loop tag? -
hasImpl
was already registered using riot.tag? -
item
loop item in the loop assigned to this instance
-
-
innerHTML
html that can be used replacing a nestedyield
tag in its template
For example using ES2015:
class MyTag extends riot.Tag {
constructor(el) {
super({ tmpl: MyTag.template() }, { root: el })
this.msg = 'hello'
}
bye() {
this.msg = 'goodbye'
}
static template() {
return `<p onclick="{ bye }">{ msg }</p>`
}
}
new MyTag(document.getElementById('my-div')).mount()
The riot.Tag
method is not recommended. You should use it only if you need to achieve special features not available with the previous riot methods