bartblast

bartblast

Creator of Hologram

Time for Hologram <> JavaScript Interop - What Would You Like to See?

It’s time to implement JavaScript interop for Hologram!

Eventually, there will be Hologram wrappers for most APIs, but sometimes we’ll need escape hatches - especially when working with legacy apps or integrating 3rd party libraries. Things like:

  • Integrating charting libraries (Chart.js, D3, etc.)
  • Using JavaScript-only APIs (Web APIs, browser-specific features)
  • Calling into existing JavaScript codebases
  • Leveraging the vast npm ecosystem

How would you envision a Hologram <> JavaScript interop API/DSL?

Some questions to spark discussion:

  • Should it be declarative or imperative?
  • How should data be marshaled between Elixir and JavaScript?
  • What would the ideal developer experience look like?
  • Are there specific JavaScript libraries you’re eager to use?
  • How should errors be handled across the boundary?

I have some ideas brewing, but I don’t want to bias the discussion by sharing them upfront. I’m genuinely curious about your use cases and what would make the most sense from a developer ergonomics perspective.

Looking forward to hearing your thoughts!

Most Liked

olivermt

olivermt

If I want to use google maps I am not looking to avoid javascript, I want to use javascript in the most practical manner possible.

Hologram is about isomorphic solution to 80-90% of your app, then for the rest where I can use pre-built stuff that is supported by a profitable business I just want a very ergonomic way to do javascript.

I do not think Bart spending time re-implementing Javascript in elixir is a good use of his time for that :person_shrugging:

bartblast

bartblast

Creator of Hologram

I’d prefer to avoid basing architectural decisions on polls though :wink: Not that I don’t like polls, but I’m trying to provoke a deeper discussion here and am more interested in understanding the deeper trade-offs for Hologram’s specific context.

I’m honestly on the fence here and looking for someone to convince me why one of these approaches is genuinely better than the others. I don’t really care if something is familiar - what I care about is the best DX in general. Sure, familiarity might be part of DX, but there are many other factors like ease of use and ease of maintenance.

olivermt

olivermt

For me the usecase is very straight forward and I suggest you even use it both as a thing to prototype with and as a showcase of interop.

I want to do a <div id=”map”/> and then initialize google maps on it.

In regular liveview this would just mean setting phx-update=”ignore” on it and start mapping JS hook events.

In Hologram I have no idea what would be most idiomatic since I haven’t really dug in yet due to lack of said JS interop.

I propose three usecases:

  1. Get the corners of the map (essentially the lon/lat of top left + lower right)
  2. Add a marker (ideally with some props like marker color etc)
  3. Delete a marker (this means you need to thread through back to Hologram the ID of an added marker)
bartblast

bartblast

Creator of Hologram

Let me clarify my current thinking on Hologram’s JS interop direction.

@Eiji - your examples are really helpful and show how high-level Hologram modules for abstracting JS Web APIs could work (like Hologram.DOM.query_selector, Hologram.DOM.add_event_listener, etc.). That’s a compelling proposition and we may very well go that way once simpler primitives are implemented and test themselves in battle.
But for now, I’m focusing on the lower-level foundation - just enabling basic interfacing between the Elixir world and JS world. The goal is simple: allow calling JS code from Hologram and vice versa, something more primitive that those higher-level APIs could be built on top of - something that enables calling Web APIs or interfacing with existing JS code like in the example described by @olivermt.

I’ve been analyzing different approaches to JS interop across languages and frameworks and found three main categories that could apply to Hologram.

1. Messaga passing

The first approach is message passing, like Elm’s ports (as mentioned by @kingdomcoder) or Phoenix LiveView hooks.

In Elm, you define ports for sending data out and subscribing to data coming in:

port sendData : String -> Cmd msg
port receiveData : (String -> msg) -> Sub msg

Then in JavaScript, you connect to these ports:

// Listen to data sent from Elm
app.ports.sendData.subscribe(function(data) {
    console.log("Received from Elm:", data);
});

// Send data to Elm
app.ports.receiveData.send("Hello from JS")

LiveView uses a similar pattern - it communicates with the JS world through hooks.

Pros: Clear boundaries between language worlds, explicit control over data flow
Cons: Communication overhead, forces async patterns even for simple operations

2. Foreign Function Interface (FFI)

The second is Foreign Function Interface (FFI), like Gleam uses. You declare external functions that map to JavaScript:

@external(javascript, "./my_js_file.mjs", "greet")
pub fn greet(name: String) -> String

With corresponding JavaScript:

export function greet(name) {
    return `Hello, ${name}!`;
}

This pattern is actually very common - most bindings with C/C++ libraries use this approach, and even Rust NAPI works similarly where you declare foreign functions that bridge between languages. For Hologram, this could look like declaring JS functions directly in Elixir modules.

Pros: Direct function calls, minimal overhead
Cons: Manual binding maintenance, potential runtime errors

3. Native compilation/interop

The third approach is native compilation/interop, like Kotlin/JS. Since the code compiles to JavaScript, you can directly interface with JS:

external fun alert(message: String)
external val console: Console

fun main() {
    alert("Hello from Kotlin!")
    console.log("Direct JS access")
}

Pros: Natural integration, full ecosystem access
Cons: Compilation complexity, language semantic mismatches

For Hologram, interestingly, the third approach doesn’t translate that well. While Hologram does compile to JavaScript, it uses its own client-side Elixir runtime rather than generating idiomatic JavaScript. This means we’re running Elixir semantics on top of JavaScript, and the different syntax and data types between JavaScript and Elixir (atoms, tuples, pattern matching, immutable data structures) don’t have direct JavaScript equivalents.


What do you think? Which approach resonates most with your use cases?

jam

jam

At the moment, I’d vote 2. Seems simplest to me and feels like the most general / flexible which I think would be important. Though I would like to see some examples of 1 in the Hologram context.

Where Next?

Popular in Discussions Top

New
krainboltgreene
Today I noticed that when defining a embeds_many the new struct has a default of [] which is confusing since: You can have jsonb[] colu...
New
bartblast
With the core component system and HTTP/WebSocket infrastructure solid, it’s time to tackle Pub/Sub support. What We Have vs What’s Miss...
New
AstonJ
Phil just posted this on EFS: …interesting that some of the key updates to JavaScript appear heavily influenced by (or blatantly copied...
New
rump13
Hi everyone, I’ve been following Elixir since around 2016 and tinkering with it on and off, but I haven’t had the opportunity to use it ...
New
AstonJ
Bart’s talk about Hologram got me wondering what kind of apps or components people are thinking about building (or think could be built) ...
New
tcoopman
Yesterday I watched OpenTelemetry: From Desire to Dashboard and it triggered me to take a new look at telemetry in Elixir. But I don’t k...
New
ashkan117
I’m wondering how do people structure their JSON Api’s with Phoenix. Using the blogs example, let’s say I have a blogs view like the foll...
New
garrison
I have been thinking about how I might write a new web framework in Elixir. (Not committing to anything, just thinking about it.) One th...
New
AstonJ
Inspired by Andrew’s post in another thread about types: If the main benefit of static typing is to catch errors, and most people think...
New

Other popular topics Top

josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
977 41022 311
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: https://hexdocs.pm/ecto/Ecto.Schema.html#module-...
New
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New

We're in Beta

About us Mission Statement