Docs
TIBET Essentials
Welcome to the second tutorial in our "Hello World!" series.
This tutorial builds on the TIBET Quickstart Guide so if you haven't worked through that tutorial do that first. It's ok, we'll be here when you get back ;).
The concrete steps we'll go through in this tutorial are summarized in the
tl;dr
section below. You can do the tl;dr
version, or follow the full
explanations in the 'Step By Step' section.
Here we go…
tl;dr
Start your application using tibet start
:
$ tibet start
...
Electron projects are good to go. Server-based projects should load http://127.0.0.1:1407#?boot.profile=development
in a supported browser such as Chrome or Edge Chromium.
Create a tag for date/time data using tibet type
with --dna computedtag
:
$ tibet type hello:now --dna computedtag
Edit ~app_tags/APP.hello.now/APP.hello.now.js
so it returns a new element
containing the current date/time value when asked to transform:
APP.hello.now.Type.defineMethod('tagCompile',
function(aRequest) {
var elem;
// Get the initiating element.
if (!TP.isElement(elem = aRequest.at('node'))) {
return;
}
// Set its content to the date.
TP.nodeSetContent(elem, (new Date()).toString());
// Return the element.
return elem;
});
Ensure APP.hello.now.js
includes an event handler for TIBET's UIActivate
signal. This will update the date/time whenever the tag is activated (vi mouse or keyboard). Add the handler using defineHandler
as shown here:
APP.hello.now.Inst.defineHandler('UIActivate',
function(aSignal) {
var target,
tag;
target = aSignal.getTarget();
tag = TP.wrap(target);
tag.set('value', new Date().toString());
});
Edit the ~app_tags/APP.hello.app/APP.hello.app.xhtml
template to hold an
instance of both our hello:world
and new hello:now
tags:
<div tibet:tag="hello:app">
<hello:world/>
<hello:now/>
</div>
Once you've made the previous changes your screen should immediately refresh to show both Hello World! and the date/time at the time the page rendered:

Thanks to the event handler we created for UIActivate
, clicking the date/time
should automatically refresh the displayed data.
That's a lightning-fast intro to TIBET computed tags and event handling. Obviously there's a lot more to each of these subjects but hopefully this example further shows how TIBET lets you focus on tags and types with minimal coding.
For a full discussion of each of the previous steps read on.
Step By Step…
Before we dive deeply into our next steps make sure your hello
project is running.
Open a terminal, cd to your project home, and execute tibet start
:
cd ${project_home}
tibet start
,`
__,~//`
,///,_ .~////////'`
'///////, //////''`
'//, ///'`
'/_/'
`
//////////////////// /////////////////// ////
`//'````````````/// `//'``````````````` '''
/` // /'
/ // '/
,/____ /' ,/_____
/////////;;,,_ // ,//////////;,_
`'/,_ '/ `'///,_
`'/,_ / '//,
'/,/, '/_
`/, `/,
' `/
'/
/
...
...
...
If you haven't changed anything after working through the Quickstart Guide you should see something like:

With our project back up and running it's time to tackle the next step…
Computed Tags
When you need more precision in rendering your tags than you can get with templating, TIBET offers another approach to tag authoring using what we call 'computed tags'.
A 'computed' tag in TIBET is a tag whose rendered markup is produced by JavaScript rather than an external template file.
hello:now
To create a simple example of a computed tag let's build another custom tag,
this time one that outputs the current date/time when it renders. We'll call
this tag <hello:now/>
.
We could do this task using handlebars-style substitution syntax in a templated tag but for purposes of this tutorial we'll create a computed tag instead.
Create a new computed tag by using --dna computedtag
with the tibet type
command:
$ tibet type hello:now --dna computedtag
In response to this command TIBET will generate a tag type and associated test file, hot patching them into our application. No template file will be created since this is a computed tag.
To keep things simple let's add our new tag to the <hello:app/>
template,
adjusting it so we get both <hello:world/>
and <hello:now/>
output in our
home page.
Edit the APP.hello.app.xhtml
template to say hello once and tell the time.
<div tibet:tag="hello:app">
<hello:world/>
<hello:now/>
</div>
Save your template with the new hello:now
tag and you should see:

What just happened?
We created a new computed tag, added it to our app tag template, and we get a
link identifying the tag location in our UI. That link is an indication our new
type is working as expected. What we're seeing is the default implementation of
a computed tag's tagCompile
method.
Click that <hello:now/>
link:

Newly created computed tags running outside of the Lama™ will alert()
you to update the tag's
tagCompile
method, a simple way of helping you to work iteratively from
definition through refinement. (In the Lama you'd be taken directly to that
method for editing).
As the link alert suggests, let's refine the hello:now
tagCompile method next.
tagCompile
When TIBET processes tags it invokes a number of methods on the types which
support those tags. The tagCompile
method is perhaps the most commonly used of
those since it's the method responsible for converting the authored form of the
tag into a renderable form.
We'll start by taking a look at the tagCompile
stub generated by tibet tag
in the source file ~app_tags/APP.hello.now/APP.hello.now.js
.
Open ~app_tags/APP.hello.now/APP.hello.now.js
, our hello:now
type's source:
/**
* @type {APP.hello.now}
* @summary A computed tag which...
*/
TP.core.ComputedTag.defineSubtype('APP.hello:now');
APP.hello.now.Type.defineMethod('tagCompile',
function(aRequest) {
/**
* @method tagCompile
* @synopsis Convert instances of the tag into their XHTML form.
* @param {TP.sig.Request} aRequest A request containing the tag element
* to convert along with other optional processing parameters.
* @returns {Element|Array<Element>} The element(s) to replace the inbound
* element with in the final DOM.
*/
return this.callNextMethod();
});
Since this is our first deep look at TIBET code let's take it a line at a time. It's a heavily-commented file with only 5 lines of executable code.
Line 1
TP.core.ComputedTag.defineSubtype('APP.hello:now');
Much like our earlier look at the hello:app
source file, the first line in
many TIBET files will be a line that invokes defineSubtype
to create a new
type. In this case we create a new TP.core.ComputedTag
subtype named
'APP.hello.now'.
Line 2
APP.hello.now.Type.defineMethod('tagCompile',
We begin the actual implementation by defining a method on our new hello:now
type to handle tagCompile
processing. The first parameter to defineMethod
is the method name.
TIBET methods are always defined using the `defineMethod` method, one of a set of meta-methods TIBET uses to help manage Type definition. Using so-called `method methods` is a best practice as described in JavaScript: The Good Parts™
In this case we want our tagCompile
method to be a type method so we add
a .Type
qualifier to target the type. If we wanted an instance method we'd add
.Inst
. If we wanted a 'local' method, a method unique to a single object, we
leave off the 'Type' or 'Inst' qualifier and invoke defineMethod
directly on
the targeted object.
Line 3
function(aRequest) {
With defineMethod
's second parameter we're providing the method body, the
function that will do the work of transforming the tag. Virtually all tag
processing methods take a single parameter, a TIBET Request
object, as shown
above.
NOTE: Do not use arrow functions for method bodies. Arrow functions have unique binding behavior that is incompatible with object-oriented binding of TIBET methods. Arrow functions are best reserved for iterators in TIBET.
Line 4
return this.callNextMethod();
Now things get a little more interesting.
TIBET is unabashedly Object-Oriented. As a result we often need to invoke the supertype version of a method. In this case we're asking our stub to do just that, to call 'the next method' up the chain without requiring hard-coded references or duplicating the argument list.
Since we subtyped TP.core.ComputedTag
that type will be checked for
tagCompile
and the search will continue up through the type
hierarchy until an implementation is found.
If you're used to C++, Java, or other JS libraries that statement should give you pause.
Many popular OO languages don't have true type inheritance, they have 'static methods'. That's not quite the same since static methods are local to a type and don't support interitance.
TIBET's OO infrastructure is modeled on Smalltalk, with a dash of Traits thrown in to support composition in a predictable, controllable fashion. TIBET lets types inherit methods and attributes, just like instances.
Line 5
});
Close method body, close defineMethod
parameter list, end statement.
Done.
With our review of the stub implementation complete our next task is to create a real one.
tagCompile v2
In the version of our tagCompile
method below we've replaced our stub's
callNextMethod()
logic with a full implementation.
Note that there's no constraint on what the `tagCompile` method does, only that it return whatever node (element, document fragment, etc) forms the replacement content.
Edit your version of APP.hello.now.js
to include this implementation:
APP.hello.now.Type.defineMethod('tagCompile',
function(aRequest) {
var elem;
// Get the initiating element.
if (!TP.isElement(elem = aRequest.at('node'))) {
return;
}
// Set its content to the date.
TP.nodeSetContent(elem, (new Date()).toString());
// Return the element.
return elem;
});
Let's look at this chunk by chunk.
Get the initiating element
The first step is to access the node in the document representing our authored
tag. The request parameter's at
method can give us that by requesting the
node
property. We verify we get a valid element from the request using the
TP.isElement()
primitive:
// Get the initiating element.
if (!TP.isElement(elem = aRequest.at('node'))) {
return;
}
Set the content of the element
Next we set the content of the element to be the String representation of a new Date:
// Set its content to the date.
TP.nodeSetContent(elem, (new Date()).toString());
Return the element to be rendered.
Finally, we return the node (typically an Element
or DocumentFragment
) to be
rendered in place of the original node. In this case we return the original
element since we don't need a replacement node, we just want to update the
current element's content in place.
// Return the element.
return elem;
Save these changes and our screen should now display:

Success!
Let's run our tests again. This time let's just test our new tag…
Change to an available terminal and enter tibet test APP.hello.now
:
$ tibet test APP.hello.now
# Loading TIBET platform at 2019-11-09T17:43:17.668Z
# TIBET reflection suite loaded and active in 5219ms
# Running Type tests for APP.hello.now
# TIBET starting test run
# 1 suite(s) found
1..1
#
# tibet test APP.hello.now.Type --suite='APP.hello:now suite'
ok - Is a TP.core.ComputedTag tag.
# pass: 1 total, 1 pass, 0 fail, 0 error, 0 skip, 0 todo, 0 only.
#
# PASS: 1 total, 1 pass, 0 fail, 0 error, 0 skip, 0 todo, 0 only.
# Running Inst tests for APP.hello.now
# TIBET starting test run
0..0
# PASS: 0 pass, 0 fail, 0 error, 0 skip, 0 todo.
# Running Local tests for APP.hello.now
# TIBET starting test run
0..0
# PASS: 0 pass, 0 fail, 0 error, 0 skip, 0 todo.
# Finished in 4270 ms w/TSH exec time of 204 ms.
All good. We just tested a specific type. But how?
Like virtually all of TIBET, TIBET's test harness isn't page-based, it's object-based. The tests TIBET generates when we create a new type are associated with that type.
Running tibet test {typename}
tells TIBET to load our application and use
reflection to run any tests it finds. By associating tests with objects you can
keep your testing focused, improve cycle times, and support smarter forms of
code coverage analysis.
Recap
Using the tibet type
command (with a --dna computedtag
option) we've created
a new tag that renders based on a JavaScript method on the tag type, the
tagCompile
method.
Our current implementation simply outputs the current Date.now()
value but
complex logic is easy to support using this approach.
With the "look" in place, the next step is to add behavior ("feel") to our tag.
Tag Behavior
When we think of behavior in JavaScript terms we're typically thinking about how an object responds to events. Event-driven development is central to web development, particularly client-side web development.
A key feature of TIBET is its signaling subsystem, a set of components which unify how events work across browsers (and across the main and renderer processes in Electron) while also supporting non-native events. In TIBET you work with Signal instances for DOM events, Exceptions, state changes, etc.
For this tutorial our goal is to add reusable behavior to our hello:now
tag so it will update its date/time display any time we activate (click) it. We
do that via signal handling.
defineHandler
To define a signal handler we use the defineHandler
method, a variant of
TIBET's defineMethod
method that's specific to signal handlers. As with
defineMethod
the first parameter is the handler name and the second parameter
is the handler body (function).
Because we want to add behavior to hello:now
tags we will define our event
handler in the JavaScript source file specific to that tag. This helps keep
functionality organized.
Note that TIBET does not require all functionality for a type to be defined in a single file. You are free to alter or extend features of a tag in separate files.
Edit ~app_tags/APP.hello.now/APP.hello.now.js
and add the following handler:
APP.hello.now.Inst.defineHandler('UIActivate', function(aSignal) {
alert('UIActivate');
});
In the code above we define a signal handler for UIActivate
signals received
by instances of hello:now
tags (thanks to the Inst
qualifier).
Recall that type methods use .Type
, instance methods use .Inst
, and local
methods use no qualifier. In all cases the targeted object receives the method.
If you're wondering what UIActivate
is, it's a TIBET signal which generalizes
click
and keyup
and is one of a number of 'UI Signals' TIBET provides to
enhance accessibility and testability across browsers and input devices.
Note that we don't need to set up or tear down observations or do any other
boilerplate coding. All hello:now
tags will automatically respond to
UIActivate
simply by virtue of our defining a handler for that signal in
our tag implementation.
Save your changes, then click on the text of the hello:now
tag in your UI:

With this simple action we've confirmed our event handler is operational.
Notice that we didn't reload, TIBET hot-patched our tag implementation with the new functionality and all previously-rendered instances of the tag automatically get the new behavior.
Signal Data
We still need to make our tag update its content in response to activation. We
do that by leveraging data in the Signal
instance provided to the signal
handler.
Edit ~app_tags/APP.hello.now/APP.hello.now.js
again, updating the handler to match:
APP.hello.now.Inst.defineHandler('UIActivate', function(aSignal) {
var target,
tag;
target = aSignal.getTarget();
tag = TP.wrap(target);
tag.set('value', new Date().toString());
});
In the code above we access the signal's target via getTarget
. This is the
low-level node that received the initial event, much as we'd expect from a
normal DOM event handler.
The next line wraps that low-level element in the best-fit TIBET type, in
this case an instance of our APP.hello.now
type, granting access to the
tag's instance methods.
The final line leverages TIBET's 'getter/setter' syntax via set()
, ultimately
triggering a call to setValue
on our tag.
Note that this method relies on polymorphism in that setting the value
of
different tag types has consistent semantics but unique results. For an input
field, this would set its .value
, property but because our target here is an
inline, non-form element, setValue
instead sets its content (innerHTML in this
case).
Save the new handler definition and then click on the date in the
hello:now
tag.
The hello:now
tag should display the current time each time we click. It's
that easy.
Recap
In this section we used the defineHandler
method to add a signal handler
to our hello:now
tag. Our new signal handler updates the tag's time display
whenever it receives a UIActivate
signal, expanding the value of our
reusable component.
As with our previous efforts we didn't have to reload the page to activate this behavior, we simply edited the source file and saved our changes. TIBET did the rest.
Of special interest is that clicking on a previously rendered tag "just worked". There was no need to set up/tear down listeners or do other boilerplate coding for events.
Summary
This "essentials" guide built upon the foundation created in the TIBET Quickstart Guide.
To kick things off we added a new custom hello:now
tag which leverages a
JavaScript method to render the current date and time.
Next we expanded our hello:now
tag's functionality by adding behavior to all
hello:now
tags so they update their display whenever they receive a
UIActivate
signal.
In particular, we updated tag behavior without any add/remove listener overhead, reducing boilerplate and the potential for memory leaks, duplicate, or dangling listener registrations.
TIBET has a lot more to offer but hopefully this further exploration of a simple
hello
application has helped reinforce one of the core things that makes TIBET
special, namely a development process focused on tags, not code.
We invite you to continue to explore TIBET by checking out the entire TIBET platform, particularly the TIBET Lama, our revolutionary web development IDE.