SkillAgentSearch skills...

Tvdml

Small library for creating tvOS apps with React.js and TVML

Install / Use

/learn @a-ignatov-parc/Tvdml
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

TVDML CircleCI

<!-- START doctoc generated TOC please keep comment here to allow auto update --> <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> <!-- END doctoc generated TOC please keep comment here to allow auto update -->

New!

This is the new version of tvdml, 6.X.

Update highlights

  • Switched TVML renderer to React.js (Breaking).
  • Unified different ways to create TVML documents (Breaking).
  • Simpler syntax to create stylesheets using <style> element (Breaking).
  • Improved Menu button detection.
  • Changed TVDML.renderModal() rerendering behavior (Breaking).

Migration guide

Check out migration guide from 5.X.

For the older version of tvdml, refer to the 5.X branch.

Intro

This is a library that's the main goal is to greatly simplify app development for Apple TV using React.js and provide tools to solve problems like:

  • React.js integration with TVML and TVJS.
  • Routing.
  • Event binding.
  • "Menu" button detection.

System Requirements

Starting from 4.X TVDML drops support for tvOS < 10. If you need that support please consider using 3.X.

Getting started

TVDML is shipping as npm package and can be installed with npm or yarn. In addition you'll need to install React.js.

npm install --save tvdml react

Or using yarn

yarn add tvdml react

TVDML is written in ES6 and built using UMD wrapper so it can be used in any environment with any of this ways:

// Directly from global scope.
App.onLaunch = function() {
  console.log(TVDML);
}

// Or with CommonJS if you are using bundlers like browserify.
var TVDML = require('tvdml');

// Or with ES6 imports.
import * as TVDML from 'tvdml';

// You can use ES6 destructuring if you need only few
// of the provided features.
import { subscribe, handleRoute, navigate } from 'tvdml';

// Or even require modules from their sources.
import { handleRoute, navigate } from 'tvdml/src/navigation';

Requiring modules from their sources can help you decrease app size if you are using rollup for your builds.

Despite being written totally in ES6 TVDML is not forcing you to use it.

But you should agree that this...

App.onLaunch = function(options) {
  evaluateScripts([
    options.BASEURL + 'libs/tvdml.js',
    options.BASEURL + 'libs/react.js',
  ], function(success) {
    if (success) {
      TVDML
        .render(function(payload) {
          return React.createElement(
            'document',
            null,
            React.createElement(
              'alertTemplate',
              null,
              React.createElement(
                'title',
                null,
                'Hello world'
              )
            )
          );
        })
        .sink();
    }
  });
}

Doesn't look as nice as this

import React from 'react';
import * as TVDML from 'tvdml';

TVDML
  .subscribe(TVDML.event.LAUNCH)
  .pipe(TVDML.render(payload => (
    <document>
      <alertTemplate>
        <title>Hello world</title>
      </alertTemplate>
    </document>
  )));

So what we need to be able to write code as in second example? Well it's not that simple but this tvdml-boilerplate repo will shed the light on basic build configuration.

Well! Now we know how to write apps using ES6 and JSX so let's start from the basic features!

Routing

tvOS provided great foundation to write apps using TVML and TVJS. But you need somehow to react on user's activity and map it to the UI.

To help you solve this issues TVDML provides navigation module.

import React from 'react';
import * as TVDML from 'tvdml';

TVDML
  .subscribe(TVDML.event.LAUNCH)
  .pipe(() => TVDML.navigate('start'));

TVDML
  .handleRoute('start')
  .pipe(TVDML.render(() => (
    <document>
      <alertTemplate>
        <title>This is initial view</title>
        <description>You can now navigate to another view</description>
        <button onSelect={event => TVDML.navigate('next')}>
          <text>Go to next page</text>
        </button>
      </alertTemplate>
    </document>
  )));

TVDML
  .handleRoute('next')
  .pipe(TVDML.render(() => (
    <document>
      <alertTemplate>
        <title>This is next view</title>
        <description>Now you know how to use routes!</description>
      </alertTemplate>
    </document>
  )));

This is a small example of navigation and rendering modules usage which helps handle routes and show views to the user.

Here is a complete navigation module api:

  • TVDML.handleRoute(routeName) — Creates pipeline for route handling. Only one pipeline can be created for the route. Otherwise it will throw error.

  • TVDML.dismissRoute(routeName) — Destroy previously created route pipeline. Can destroy only created pipelines. Otherwise it will throw error.

  • TVDML.navigate(routeName[, params][, isRedirect]) — Navigation trigger. Will invoke registered route pipeline with passed params if they are specified. Route pipeline will result in creating new navigation document. if param isRedirect is passed then route pipeline will replace current navigation document with new one.

  • TVDML.redirect(routeName[, params]) — Same as TVDML.navigate(routeName, params, true).

import * as TVDML from 'tvdml';

TVDML
  .subscribe(TVDML.event.LAUNCH)
  .pipe(() => TVDML.navigate('start', { foo: 'bar' }));

// To create route handler use `handleRoute` method.
TVDML
  .handleRoute('start')
  .pipe(payload => {
    const {
      route,
      redirect,
      navigation,
    } = payload;

    console.log(route); // 'start'
    console.log(redirect); // false
    console.log(navigation); // { foo: 'bar' }
  });

// `dismissRoute` method will help you destroy route handler.
TVDML.dismissRoute('start');

Here is a list of predefined constants for system events:

  • TVDML.event.EXIT
  • TVDML.event.ERROR
  • TVDML.event.LAUNCH
  • TVDML.event.RELOAD
  • TVDML.event.RESUME
  • TVDML.event.SUSPEND

This events are related to system handlers: App.onLaunch, App.onExit etc.

Why would you use this events and not system handlers directly? Handlers can be assigned only once and events can be attached multiple times. But no one force you to use them.

You can add event listeners like this:

import * as TVDML from 'tvdml';

TVDML
  .subscribe(TVDML.event.LAUNCH)
  .pipe(eventSymbol => console.log('App is launched!'));

const suspendEventPipeline = TVDML
  .subscribe(TVDML.event.SUSPEND)
  .pipe(eventSymbol => console.log('App is sent to background'));

// To destroy event pipeline use `unsubscribe` method.
suspendEventPipeline.unsubscribe();

To know more about how pipelines works check Pipelines section.

Also there are some predefined routes that may help you:

  • TVDML.route.NOT_FOUND — Will be invoked when navigation module was unable to find match to requested route.

The next big thing is...

Using React.js

With TVDML your main way to create documents will be React.js.

Here is a list of all available documents in TVML.

To render any react component you need to provide rendering factory to TVDML.render pipeline.

Pipeline's payload will be passed as the first argument to rendering factory so you'll be able to map it's props to rendering tree.

import React from 'react';
import * as TVDML from 'tvdml';

TVDML
  .subscribe(TVDML.event.LAUNCH)
  .pipe(TVDML.render(payload => (
    <document>
      <alertTemplate>
        <title>Hello world</title>
      </alertTemplate>
    </document>
  )));

Here is how to render any component you like:

import React from 'react';
import PropTypes from 'prop-types';
import * as TVDML from 'tvdml';

function Hello(props) {
  return (
    <document>
      <alertTemplate>
        <title>Hello {props.name}</title>
      </alertTemplate>
    </document>
  );
}

Hello.propTypes = {
  name: PropTypes.string,
};

Hello.defaultProps = {
  name: 'world',
};

TVDML
  .subscribe(TVDML.event.LAUNCH)
  .pipe(TVDML.render(payload => (
    <Hello name="user" />
  )));

It's just plain old React.js.

But there are some things you need to remember about TVML and React.js.

Because TVML and TVJS are not your normal browser they have some

Related Skills

View on GitHub
GitHub Stars65
CategoryDevelopment
Updated12d ago
Forks9

Languages

JavaScript

Security Score

100/100

Audited on Mar 28, 2026

No findings