Embedding Dart in HTML

Written by Sigmund Cherem and Vijay Menon
October 2011
Updated April 2012

Dart is a new structured programming language for the browser. Like JavaScript, Dart programs can be directly embedded on HTML pages served to the browser.

This document describes syntax and semantics for how Dart is embedded in a web page. An HTML page with Dart can be translated to a semantically equivalent page embedding JavaScript.

Dart MIME type

HTML script tags provide a type attribute to define the language of the script. For Dart, this attribute has the value 'application/dart'.

Like other script tags, the script contents can be inlined as the body of the script tag or specified by reference via a URL using the script tag’s src attribute.

The Dart script must have a visible top-level function called main(), either declared directly in the script or in a sourced/imported file. The browser will invoke main() when the page is loaded.

The Dart script may have optional #source and #import directives. Dart scripts include other scripts using the #source directive. Dart scripts can use other libraries with the #import directive.

Fundamental differences from JavaScript

Embedding Dart code is different from embedding JavaScript in a few ways.

Isolated script tags

Every HTML page can have multiple Dart script tags, but each Dart script tag in a page runs in isolation. This fundamentally differs from the way that JavaScript is embedded in HTML—in JavaScript, declarations across multiple script tags are combined together in the same namespace. In Dart, code in one script tag cannot directly access code defined in another. If a script wishes to load code from a different URL, it must do so via #source or #import. Each script tag must define its own main() entry point in order to run.

Delayed execution

Unlike in JavaScript, top-level Dart constructs (such as interfaces, classes, and functions) are declarative. Each Dart application (defined via a script tag) provides an explicit main() entry point that is invoked by the browser when it is ready to run.

By default, each Dart script tag’s main() is invoked on the DOMContentLoaded event. Ordering across script tags is not guaranteed. This has a few consequences:

  1. All script tags with the 'application/dart' MIME type in the page can be loaded asynchronously/concurrently. (That is, HTML5 async and defer tags are hints that do not affect semantics.)
  2. Dart code executes only after the page is parsed. Dart programmers can assume that the DOM is fully loaded.

No inline event listeners

We disallow inline event listeners of the form:

<div onclick="foo()">Click this text.</div> 

With JavaScript, programmers can embed inline event listener code directly onto HTML nodes. However, this is typically discouraged in modern JavaScript applications. HTML pages generally render more quickly if listeners are added programmatically afterwards. Modern security guidelines also discourage inline code. As such, we propose to not allow inline Dart listeners.

Examples

Here is a simple Hello World in HTML using Dart. This script defines its own isolate/library. The main() method is implicitly the entry point.

<html>
  <body>
    <script type='application/dart'>
      void main() {
        HTMLElement element = document.getElementById('message');
        element.innerHTML = 'Hello from Dart';
      }
    </script>
    <div id='message'></div>
  </body>
</html>

The div element above is guaranteed to exist by the time the Dart code starts running.

In contrast to the previous example, the following is an error:

<html>
  <body>
    <script type='application/dart'>
      void hello(String text) {
        HTMLElement element = document.getElementById('message');
        element.innerHTML = text;
      } // This tag triggers a warning as no main() is defined.
    </script>
    <script type="application/dart">
      void main() {
        hello('Hello from Dart'); // hello() will not resolve.
      }
    </script>
    <div id="message"></div>
  </body>
</html>

To incorporate external code, use a #source or #import directive instead. For example, suppose the file Hello.dart defines the hello() method shown above. Then the following executes as expected:

<html>
  <body>
    <script type='application/dart'>
      #source(Hello.dart)
      void main() {
        hello('Hello from Dart');
      }
    </script>
    <div id="message"></div>
  </body>
</html>