Interop
Interop is extremely important for any language that compiles to JavaScript. To be viable in a commercial setting, you need to be able to reuse helpful libraries and tools to get things done quickly. This section covers how to embed Elm in HTML and how to communicate with JavaScript.

HTML Embedding

Elm can be embedded directly in a `<div>`. This lets you easily integrate Elm into a larger JS project.

Say you have a simple program Stamper.elm that lets you stamp shapes by clicking. Compile it with:

elm-make Stamper.elm --output elm.js

This will result in a file named `elm.js`. This JS file contains everything necessary for embedding in HTML.

In our HTML file, we add a `<script>` below the `<body>` that includes the following code:

<html>
<head>
<script src=elm.js> </script>
<head>

<body>
<div id="stamper" style="width:440px; height:140px;"> </div>
</body>

<script>
var div = document.getElementById ('stamper');
Elm.embed (Elm.Stamper , div);
</script>
</html>
The `Elm.embed` function takes two arguments:
  • 1. An Elm module
      all modules are prefixed with `Elm` in JS to avoid namespace pollution,
      so our `Stamper` module becomes `Elm.Stamper`
  • 2. A `<div>` to embed the program in

    That's it!

    Note that `Window.dimensions` and `Mouse.position` will be relative to the `<div>`, not the entire page. This means the `Stamper` code still fills the `<div>` entirely and handles clicks appropriately.

    Other ways to embed Elm

    The example above embeds in a `<div>` but it is also possible to create Elm components that run fullscreen and ones that have no graphics at all:
    // fullscreen version of Stamper
    Elm.fullscreen (Elm.Stamper);
    
    // Stamper with no graphics
    Elm.worker (Elm.Stamper);
    

    You can also generate the HTML automatically by specifying an HTML output file with

    elm-make Stamper.elm --output=Main.html

    Ports

    Ports are a general purpose way to communicate with JS. They let you send messages in and out of Elm so you can use JS whenever you need to.

    From JavaScript to Elm

    To send messages from JS to Elm, you use an incoming port like this:
    port addUser : Signal (String, UserRecord)
    This means we now have a signal in Elm called `addUser` that is updated by some code in JS. To actually send messages to this port, we would write something like this in JS:
    <script>
    var myapp = Elm.fullscreen (Elm.Stamper);
    
    myapp.ports.addUser.send (["Tom" , {age: 32 , job: "lumberjack" }]);
    myapp.ports.addUser.send (["Sue" , {age: 37 , job: "accountant" }]);
    </script>
    
    This sends two updates to Elm, automatically converting to values that work well in Elm.

    From Elm to JavaScript

    To send messages from Elm to JS, you define an outgoing port like this:
    port requestUser : Signal String port requestUser = signalOfUsersWeWantMoreInfoOn
    In this case we are taking a signal that exists in Elm and sending each of its values to JS. On the JS side, we handle these messages by subscribing to that port:
    <script>
    var myapp = Elm.fullscreen (Elm.Stamper);
    
    myapp.ports.requestUser.subscribe (databaseLookup);
    
    function databaseLookup (user)
    {
        var userInfo = database.lookup (user);
        myapp.ports.addUser.send (user, userInfo);
    }
    </script>
    
    We have subscribed to the `requestUser` port and will actually go and do the database lookup. When we get the results, we send them back into Elm using another port.

    Perhaps at some point you will need to unsubscribe from a port, in which case you would do this:

    <script>
    myapp.ports.requestUser.unsubscribe (databaseLookup);
    </script>
    

    Customs and Border Protection

    Ports must be careful about what values are allowed through. Elm is statically typed, so each port is fitted with some border protection code that ensures that type errors are kept out. Ports also do some conversions so that you get nice colloquial data structures in both Elm and JS.

    The particular types that can be sent in and out of ports is quite flexible, covering all valid JSON values.

    Specifically, incoming ports can handle all the following Elm types:

      Booleans and Strings   – both exist in Elm and JS
      Numbers                – Elm ints and floats correspond to JS numbers
      Lists                  – correspond to JS arrays
      Tuples                 – correspond to fixed-length, mixed-type JS arrays
      Records                – correspond to JavaScript objects
      Signals                – correspond to event streams in JS
      Maybes                 – `Nothing` corresponds to `null` in JS
    
    All conversions are symmetric and type safe. If someone tries to give a badly typed value to Elm it will throw an error in JS immediately. By having a border check like this, Elm code can continue to guarantee that you will never have type errors at runtime.