Component Library - Surface or LiveView?

Though Phoenix LiveView borrowed a lot of the great functionality built in Surface by @msaraiva, I do think there is still a very glaring gap. This gap is more pronounced when you intend to build a reusable component library.
At this moment there is still no easy way to bundle Javascript into the Phoenix LiveView components. For example, suppose there is some javascript that you want to execute as a hook, how do you make it into a bundle?
Surface already has this solved via Surface ( In that sense, if we want to build a really reusable component library ala Chakra UI - A simple, modular and accessible component library that gives you the building blocks you need to build your React applications. - Chakra UI (, Surface is more suited to such purpose. It is not yet possible to do it with LiveView.
Is my understanding incorrect? Am I missing anything obvious? Is there a way to ship Javascript also as part of the mix package?

1 Like

You can bundle JS with a mix project. Here’s a great project to use as an example: GitHub - maxmarcon/live_select: Dynamic selection field for LiveView

Edit to add: the user does have to include this somehow in their own JS bundle and then export the required hooks, but that’s usually like ~2 lines. See here.


To address some other bits of your post:

Surface is an amazing project that has 1000% pushed LiveView in the right direction. If I were building a component library today, however, I would absolutely target HEEx/LiveView/Phoenix.Component. I think that last one is especially interesting, a component library that supports some sense of “progressive enhancement” — components that can work in dead views via Phoenix.Component, but that might add interactivity in a LiveView context.


Likely that gap will decrease with future releases of LiveView. Though it’s currently not a standardized solution, here is another example where a LiveView component that includes a javascript hook gets installed with a mix multi_select.install task.

1 Like

Thanks @zachallaun. Firstly, that LiveSelect link really helped. It provided a good direction.
What amazes me with Surface library is how far ahead it is for that time. Thinking JS interoperabiliy, properties, events definitions for linting - just amazing what a single person could do. Take a bow @msaraiva
With Phoenix 1.7 adopting LiveView fully, I think we will find only two varieties of applications in Phoenix going on. One will be LiveView applications - and - API only applications. At this moment, it is difficult to think of the need for a regular MVC application being written in Phoenix.

1 Like

@saleyn Thanks for the link. Yes, it provided another interesting example.
I agree - the gap will decrease further. Specially, with Surface 0.9 supporting LiveView 0.18, we have a lot more interoperability.
Yeah - staying on heex/LiveView route looks the route that will have greater adoption in the community as well.
Exciting times to be a web developer.

I’ve yet to see a component library type tool, which can properly handle colocated scripts and styles, but also not force you into whatever bundler or tooling they happen to use to handle those files. I’d really love to find a well working successor to at some point, but it suffers from the same issue. Not well portable between stacks.


@LostKobrakai is an interesting one. But, that is not what I am aiming at in my question. If Phoenix can have a component library like Chakra UI, is it better to write in Surface or LiveView - which will have greater acceptability - that is all my scope was.
With one good UI library like that, Phoenix can bring insane productivity. Maybe it will revolutionize the way companies look at Web App Development.

Fair. My argument was that you’d likely want to provide source files as users will likely have their own and diverse pipelines of how to handle assets. The easiest way to do that is acting as an npm package besides being an hex package. That’s what phoenix does with all of their packages. They have a package.json in their root, which allows any npm handling tooling to interact with their assets.

Surface UI while working does seem to use custom means to bundling up those assets, which imo is convenient, but problematic when external bundlers need to integrate with those assets.

1 Like

@zachallaun and @LostKobrakai already hinted at this, but I just wanted to spell it out:

It’s actually relatively easy, and you just need to look at phoenix_live_view itself. LiveView needs a JS file to work. So how is it included in your app?

The hex package doubles as npm package by including a package.json that contains the location of the js file, so you can just do import {LiveSocket} from "phoenix_live_view" in the root file of your JS bundle. You can do that because the standard builder is esbuild, which will use your deps folder as the base folder for all dependencies (but will also look into assets so you can add stuff there as well). Things become slightly more complicated if you depart from the esbuild-based process and want to use something like Webpack: in that case you’ll need to add the hex packages as “path dependencies” in your package.json file, as explained here. What sucks about this latter approach is that you have to run a npm install --force after every update of your hex package to get the latest JS into your assets folder.

In LiveSelect I’m simply copying this simple idea :slight_smile:, and this is the best way (that I know of) for a 3rd party library to include its JS dependencies.

On the other hand, what I find really problematic is when my library wants to include some custom CSS. Currently there is no easy and portable way to do it, AFAIK. Esbuild can output css, but some folks (like me) only use tailwind-cli and that would require the user to generate and add a second css file.


FWIW, ChrisMcCord mentioned colocated JS as a goal for 1.0, although he’s not sure if it will be done in time for the initial release: Keynote: The Road To LiveView 1.0 by Chris McCord | ElixirConf EU 2023 - YouTube

Another question on this topic: are there any remaining advantages to Surface over LiveView at this point?

1 Like

While it’s been great to see LiveView adopt some of Surface’s goodies, there’s still more:

  • both scoped JS and scoped CSS
  • css_variant option on component props to auto-generate CSS class (i.e. tailwind) variants based on prop values
  • contexts are huge for making certain assigns (eg current_user) available without needed to explicitly pass them to every child component
  • Dynamic.Component and Dynamic.LiveComponent for including components with a dynamic name (eg. configurable widgets)
  • MacroComponent for creating specific components that are rendered at compile time (eg. to process static content like markdown, SVG icons, etc only once)