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

fklement
This is a thread to gather some information about the efforts of using elixir in combination with cars or vehicular systems in general. ...
New
heathen
Quite interesting article Google brought me. Didn’t find any mentions about it here. What do you think in general? Would you use togethe...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
bglusman
I’m curious how others in the community deal with first class enums… especially crossing boundaries like database, code logic, and absin...
New
Sergiusz
Hello everyone, I don’t know if my post is appropriate. If it isn’t, you can delete it. After a year of designing and defining the requ...
New
derpycoder
So, anyone got a chance to look at this?!? I’m kind of glad this came along. We can just throw this into our Auth pages and won’t have t...
New
dogweather
I’ve been brainstorming about ways to solve the N-dimensional code organization problem, and am thinking about developing a Smalltalk-lik...
New
New
puemos
I’m working on a platform that allows users to add apps and use them in a writing assistant browser extension (https://anycursor.com). C...
New
ScriptyScott
Hey Folks, I just spent the last couple of days doing a deep dive into using Swoosh with Amazon’s simple email service, check out this t...
New

Other popular topics Top

minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
yurko
Here are few pieces of (common) Linux knowledge that we use for reasonably small one server apps. We use Ubuntu but this should work for ...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New
AstonJ
by Lance Halvorsen Elixir and Phoenix are generating tremendous excitement as an unbeatable platform for building modern web application...
460 27162 124
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
magnetic
Hey :wave:t3: Elixir community, I’ve been learning Elixir, and working on some side projects. My editor of choice is VSCode, and althoug...
New

We're in Beta

About us Mission Statement