Skip to content

@tbuschto tbuschto released this Mar 19, 2020 · 4 commits to master since this release

Developer experience

New developer toolbar

The existing developer console has been replaced by new development tools. The main element is a persistent toolbar akin to a browser URL bar, sitting atop the screen and above the application UI. It provides quick access to essential development utilities. Most importantly it informs you where the application code is loaded from, allows to insert a different URL (also scannable via qr-code on Android), lets you reload the app and open the console logs.

As with the previous developer console, the new developer tools are only available when your app is build with the EnableDeveloperConsole flag. The developer tools can also be explicitly hidden when not required. This can be done via its the developer tools menu entry or by using the new devTools service API.

New and improved debugger support on Android

Tabris.js now supports the V8 inspector protocol on Android platforms. This means you have a fully-featured step-by-step debugger available to use in your favorite IDE. Source maps are applied automatically (when sideloading the code), meaning you'll see your TypeScript or JSX code when debugging and not the JavaScript output.

Project templates updated

When generating a new Tabris.js project via tabris init it can now be pre-configured for debugging via Visual Studio Code. The tslint configuration also has been replaced with similar eslint configurations, complete with TypeScript and JSX support. The questionnaire itself has been trimmed down a bit, with the option to generate Tabris.js 2.x apps no longer being available.

CLI "serve" updates

The serve command has received various improvements:

  • The new --qrcode-renderer option allows to choose a different formatting for the QR code. The default is utf8, but some terminals may not display these characters as expected. In this case setting the option to terminal will produce a larger-but-safer version of the code.
  • The colors and formatting of the printed output has been tweaked for readability.
  • The stability of the debug-connection (handling logging and auto-reload) has been improved significantly.
  • You can now have a variety of key shortcuts available to interact with the running app, such as CTRL+R for reload and CTRL+U for printing a UI tree. It is also possible to backup and restore the localStorage content.


Extended file system API

The fs object has some new methods, mostly for handling directories:

  • createDir(path) creates a new directory at the given path
  • removeDir(path) removes an empty directory
  • remove(path) removes any file or directory, empty or not
  • isFile(path) checks if the given path points to a file
  • isDir(path) checks if the given path points to a directory
  • appendToFile(path, data) adds data to a new or existing file

On Android, paths to external storage are made available via the externalFileDirs and externalCacheDirs properties.

Data binding in JavaScript/JSX

The data binding capabilities of Tabris.js rely on the TypeScript compiler (tsc) to transform non-standard syntax and include type information in the compiled code. So far this meant that only .ts and .tsx files could use data binding. This has been changed so that .js and .jsx files are also supported, as long as they are still processed by tsc. Due to the missing type information an "unsafe binding" warning will be logged in certain cases, which can be fixed by adding some type data in code.

In future releases it may be possible to suppress these warnings entirely, as well as using the API entirely without the TypeScript compiler, i.e. in "vanilla" JS.

Assets 2

@tbuschto tbuschto released this Jan 27, 2020 · 22 commits to master since this release


Widget "Row" and Layout "RowLayout"

These are exact analogues to the existing Stack widget and StackLayout.

The Row widget is a composite that is automatically arranges its children in one horizontal line, like a single-row table. The corrosponding layout manager RowLayout may also be used on Composite, Canvas, Page and Tab via their layout property.

The default vertical layout of each child is controlled by the alignment property which can be set to 'top', 'bottom', 'centerY', 'stretchY' or 'baseline'. Individual child elements can be layouted different from the default via their own layout properties.

A very simple example:

<Row alignment='top' padding={4} spacing={24} >
  <TextView>ipsum dolor</TextView>
  <TextView>sit amet</TextView>

A more elaborate example can be found here.

Canvas Method "toBlob"

This new method on the Canvas widget creates a Blob object containing the image drawn on the canvas as a compressed image file. This can be a JPEG, PNG or WebP file. (WebP is only supported on Android).

It's really simple to use:

canvas.toBlob(blob => doSomething(blob), 'image/jpeg');

The resulting image may be written to disk via the fs service or sent to a server via fetch(). It can also be set on any widget property that supports the ImageValue type.

Function "createImageBitmap" supports Canvas instances

The createImageBitmap() method can now create ImageBitmap instances from a Canvas instance. This recommended over canvas.toBlob() if the image is only used as an ImageValue on some widget and no access to the raw data is needed.

Button property "autoCapitalize"

The new property autoCapitalize controls how the button text is capitalized with the following options:

  • 'default' - The platform decides on the capitalization
  • 'none' - The text is displayed unaltered
  • 'all' - Every letter is capitalized

Data Binding

New Components "ListView" and "ItemPicker"

ListView is an extension of CollectionView that adds high-level convinience API suitable for data binding. The ItemPicker does the same for Picker. Both provide an items property that take instance of List, which is provided by the tabris-decorators module. List features a subset of the standard Array interface, but unlike arrays it can be observed. This means any change to the list is immediately applied to the widget. In case of ListView the change is even animated. Scoll position (for ListView) and selection state (for ItemPicker) are preserved if possible.

The items properties also accept arrays, but in that case changes are not tracked. Instead of modifying the array the property needs to be set to a new array instance.

Both widgets also feature new selection API that directly provide the selected item value instead of just a selection index. Callbacks are not needed anymore either, meaning ListView and ItemPicker can now be more conviniently created in JSX. To do so the <ListView> element needs to contain a<Cell> element which is duplicated as often as needed. Multiple <Cell> elements may be given to display different item types.


      <ListView stretch items={generate(20)}>
        <Cell padding={8} height={52}>
          <TextView centerY template-text='The color of ${item.text}:' font='24px'/>
          <Composite  stretchY left='prev() 24' width={80} bind-background='item.color'/>


Event "keyPress"

On app there now is a keyPress event fired when a hardware key is pressed. Note that these events stem from physical hardware, not from the virtual keyboard. The event object provides the keys' character, keycode and various meta data. The events prevendDefault() method can be used to prevent the default action of the key so the application may define it's own behavior.

Service "sizeMeasurement"

This is a service object that can measure the size of a given text in device independent pixel (DIP). Both synchroneous and asynchroneous API is available.


New CLI "serve" options

The tabris serve command has some minor new features:

  • The --external option allows to define an URL as the only availble external address, which will then also be encoded in the QR code.
  • The --port option allows to define the actual port of the HTTP server so it matches the one given via --external.
  • With the --no-intro option the QR code is not printed to the console. However, the QR code is now always available on the HTML site served by the CLI on the default URL with no path. So if the CLI runs on port 8080, entering http://localhost:8080 in a browser will still display the code.

Repository "tabris-decorators" supports GitPod

GitPod is an online IDE that can instantly provide a ready-to-code dev environment for any GitHub repository. Thanks to the CLI updates mentioned above it is now possible to side-load a tabris project in the developer app directly from a running GitPod instance.

The "tabris-decorators" repository has been pre-configured for this use case. Upon opening the repository in GitPod a script will launch that install the tabris CLI and print a list of available examples that can be launched via npm start <example>. It is also possible to directly launch a specific example using a custom URL. For the example labeled-input this would be:

Assets 2

@tbuschto tbuschto released this Oct 16, 2019 · 7 commits to 2.x since this release

iOS 13 Compatibility

Fixed crash on startup when running on iOS 13


The following properties have been backported from the 3.x branch:

TextInput: "keyboardAppearanceMode"
app: "idleTimeoutEnabled"

Assets 2

@tbuschto tbuschto released this Oct 11, 2019 · 61 commits to master since this release

This patch release fixes compatibility with cordova plug-ins and a bug in the image scaling logic on Android.

Assets 2

@tbuschto tbuschto released this Oct 4, 2019 · 62 commits to master since this release


New Widget "CameraView"

Tabris.js 3.2 adds the ability to take images via the devices camera. In order to so so, the tabris.Device object provides a list of cameras, which can be set on CameraView to show a live preview feed. To capture
an image, simply call the asynchrenous camera.captureImage() method, which returns a Blob containing a JPEG. The existing permissions API can be used to obtain access to the camera.

Minimal Example:

const camera = device.cameras[0];
  () => = true,
  () => console.log('"camera" permission is required.'),
  (e) => console.error(e));

  <Stack stretch>
    <CameraView stretchY camera={camera}/>
    <Button text='Take picture' onSelect={captureImage}/>

async function captureImage() {
  const {image} = await camera.captureImage({flash: 'auto'});
  // do something with the "image" blob...

Blob and BitmapImage as Generic Images

A compressed image (jpeg, png) obtained as a Blob object - for example via fetch or Camera - can now used anywhere the existing API accepts an ImageValue.

Minimal Example:

  const response = await fetch('http://foobar/image.png');
  const blob = await response.blob();
  contentView.append(<ImageView stretch image={blob}/>);

The same is true for BitmapImage objects, which can be created from Blob and ImageData. That way the the image is already in memory and its size already known before it is used in the UI.

This feature will become much more powerful when the BitmapImage API is extended in future Tabris.js releases.

New TextInput properties

The messageColor property lets you control the color of the message placeholder text independently from the input text.

On Android only keyboardAppearanceMode can be used to prevent the onscreen keyboard from popping up when a TextInput is focused, or only when it is focused by touch.

Option to control CollectionView.reveal() animation

Previously it was not possible to control whether a CollectionView.reveal() operation would be executed in an animated fashion or not. Now there is parameter a parameter which allows to control this behavior. The default is to animate the reveal operation.

Data Binding

The JSX/decorators based Data Binding API (TypeScript only) has been extended to allow bindings between widgets and non-widget ("plain") objects, including change detection. Previously this was only possible in a very limited manner. This feature was added to properly support the MVVM (Model-View-ViewModel) programming pattern.

Any instance of a class using the @property decorator on its properties can be used for bindings. One-way bindings to such an object are declared via JSX. The syntax for this remains unchanged, except that it is now also possible to bind to deeply nested properties:

export class ExampleComponent extends Composite {

  @property public myObject: Model;

  constructor(properties: Properties<ExampleComponent>) {
      <Stack stretch>
        <ProgressBar bind-selection='myObject.someNumber'/>
        <TextView bind-text='myObject.otherModel.someString' text='Placeholder'/>


The above example applies values of myObject properties to ProgressBar and TextView properties. If the source values are changed, or the entire myObject object is replaced, the widget properties are updated accordingly. Should the widget properties change for some other reason the source properties keep their value.

Two-way bindings to plain objects are declared via the @bind or the @bindAll decorator (which is a shorthand). The decorators take a parameter object mapping the property of the object to any property of any component-internal child (identified via its id):

export class ExampleComponent extends Composite {

    myText: '#input1.text',
    myNumber: '#input2.selection'
  public model: Model;

  constructor(properties: Properties<ExampleComponent>) {
        <TextInput id='input1' text='Fallback Text'/>
        <Slider id='input2'/>


This applies values of model properties to TextInut and Slieder properties and vice versa. Of course, if the widget property can't change by itself (i.e. TextInput's message instead of text) this is effectively a one-way binding.



The tabris init command can now also create projects with MVVM example code, including unit tests.

New Event Handling Method "triggerAsync"

This method is an asynchronous alternative to trigger(). When called with await it pauses for all listener to resolve, including those marked async. This can be desirable - for example - to propagate errors from async listeners to the code that triggers the event, or when writing unit tests that need to verify the behavior of asynchronous code.

Internal Change: Property System Reworked

The internal property system has been partially re-written, which may cause minor differences in behavior. Most notably, properties should now behave more consistently regarding value checking and conversion/normalization. Also, properties that take objects/arrays no longer operate with safe copies. Instead they now keep the exact instance that was set (if no conversion is necessary), but makes them immutable if appropriate.

Due to this change Tabris Plug-Ins targeting 3.0 or 3.1 do not work with 3.2. New compatible versions have been released for the following plug-ins:

  • tabris-plugin-maps (6.0.0)
  • tabris-plugin-firebase (4.0.0)
  • tabris-plugin-barcode-scanner (3.0.0)

Documentation Update

The documentation has been slightly revised, most noteably featuring a more structured table of contents in the left sidebar. Also, the presentation of type information in API documents has been tweaked and now always links to the type in question, either within the Tabris.js documentation or to MDN.

Assets 2

@tbuschto tbuschto released this Aug 8, 2019


Update Version to 2.8.1
Assets 2

@tbuschto tbuschto released this Jul 30, 2019 · 94 commits to master since this release

New Permissions API

In order the access features like the devices location or camera, the user has to grant corresponding permissions to the app. Tabris 3.1 introduces the permission object that allows the app to check and request these permissions at runtime.

FormData support

Tabris.js now provides the FormData class (including related classes Blob and File) as it is specified by the W3C. It can be used in conjunction with fetch() or XMLHttpRequest to upload data in the "multipart/form-data" encoding.

Widgets API

New CanvasContext method "drawImage"

Until now the CanvasContext class implemented by Tabris.js lacked the W3C standard method drawImage. It has now been added with support for instances of the ImageBitmap class, which represent uncompressed in-memory images. ImageBitmap objects are created with the asynchronous createImageBitmap method using a Blob (containing a .jpg or .png image), ImageData or another ImageBitmap instance as the source.

New property "imageTintColor" on Button

This new property allows to tint the image displayed on a Button widget.

New property "scrollbarVisible" on CollectionView

The property works in the same fashion as scrollbarVisible on the ScrollView by showing or hiding the scroll bar.

New property "maxChars" on TextInput

Allows to limit the maximum number of characters that the user can enter into a TextInput.

New events "select" and "reselect" on Tab

The new "select" event on the Tab fires in tandem with the "select" event on the parent TabFolder, while "reselect" on the Tab fires when the tab is tapped by the user while it is already visible.

Infinite Animations

The animate method now allows Infinity as a value for the repeat option.

Assets 2

@tbuschto tbuschto released this Jul 30, 2019 · 512 commits to master since this release

This relase adds some features introduced in Tabris.js 3.0 and 3.1 to Tabris.js 2.x. Like usual it also includes some minor bugfixes.

ImageBitmap and drawImage

Until now the ConvasContext class implemented by Tabris.js completely lacked the w3c standard method drawImage. The new drawImage method takes instances of ImageBitmap, which represent uncrompressed in-memory images. ImageBitmap objects can be created with the asynchronous createImageBitmap method from a Blob contining a JPEG or PNG image.

ImageBitmap is a W3C standard and supported by all three Tabris.js 2 platforms.

Widget property "absoluteBounds"

The new property absoluteBounds provides widget bounds relative to the tabris.ui.contentView widget instead of the direct parent like bounds does.

ScrollView properties "scrollXState" and "scrollYState"

The ScrollView adds the properties scrollXState and scrollYState which indicate whether the view is currently, dragging, scrolling or in a resting position. Matching change events are available to observe these state changes while in motion.

Assets 2

@tbuschto tbuschto released this Jun 6, 2019 · 119 commits to master since this release


Correct cordova versions in FAQ
Assets 2

@tbuschto tbuschto released this May 22, 2019 · 131 commits to master since this release

Adjust console snippet for better stack trace on iOS

Unfortunately iOS stack traces skip arrow functions, which is why the
cleaned-up stack trace was empty in this snippet. (The trace function
falls back to the original stack trace.)

Add a intermediate named function to the function so we get a clean
trace on iOS.

Change-Id: I86db8a64cc4bb7bfa2c2587a701d251608ca91c5
Assets 2
You can’t perform that action at this time.