msaraiva

msaraiva

Broadway Core Team

Surface - A component-based library for Phoenix LiveView

Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative way to express and use components in Phoenix. Some of the main features include:

  • Components as modules - they can be stateless, stateful, data-only or compile-time
  • Declarative properties - explicitly declare the inputs (properties) of each component (like React)
  • An HTML-centric templating language with built-in directives (:for, :if, …) and syntactic sugar for attributes (inspired by Vue.js)
  • Contexts - allows parent components to share data with its children without passing them as properties
  • Compile-time checking of components and their properties
  • Integration with editor/tools for warnings, syntax highlighting, jump-to-definition, auto-completion and more

A work-in-progress live demo with more details is available at surface-demo.msaraiva.io.

Installation instructions and other useful information can be found at github.com/msaraiva/surface.

And finally, a VS Code extension that adds support for syntax highlighting is also available at
marketplace.visualstudio.com.

There’s still a lot of work to do and I hope some of you out there might be willing to help me in this journey. Bear in mind that the LiveView Component API has not reached a stable version yet and it’s currently under development, so although we try to keep track of the latest changes as much as possible, there might be temporary incompatibilities between Surface and Phoenix LiveView until a final version is released.

I’d like to thank @chrismccord and the Phoenix Core Team for buying the idea of reusable components and bringing the necessary basic concepts to the core API.

I also want to thank @josevalim, not only for the many valuable insights during development but also for his inestimable help with the main parser.

Happy coding!

-marlus

564 43623 214

Most Liked

msaraiva

msaraiva

Broadway Core Team

Call me stupid but can someone explain the value in having such an abstraction in practice?

I think there’s no need to call you stupid. It’s a valid question. However, I believe that either you didn’t have the opportunity to read the “Getting started” guide at surface-demo.msaraiva.io or, most likely, I did a terrible job trying to explain some of the benefits there. So, please, let me try again.

In the Grid example it looks like you could have put the <table> inside of a template in the render function

Of course I could, but then I’d have missed the whole point of demonstrating how to use children as data. The Grid example was extracted from the section called “Children as data” of the “Getting started” guide mentioned above. That guide is not meant to be a tutorial on how you should design your application, it’s just a guide with simple examples that demonstrates the main features. The way you use those features is up to you.

and it would work the same

Well, it’s an abstraction on top of EEx, so it expected to work the same. Actually, by the end of the day, anything you can do with Surface can be done with EEx, just like anything you can do with React/JSX can also be done with pure Javascript. It’s hard to know when to stop adding abstractions on top of existing ones. There is always a tradeoff.

and be more similar to how templates work with EEx.

I have no intention whatsoever to keep Surface similar to EEx. On the contrary, I don’t want any dependency between Surface’s and EEx’s syntax. Each one of them tries to solve different problems. The main issue with EEx is that it makes no distinction between plain text and HTML (or any other structured format). Everything is treated as text. When using EEx, all you end up with is a big unstructured list of lists of chunks of text, consequently, a lot of useful information that we could use in our favour to boost productivity is lost. Here are some, IMO, clear benefits of keeping that information:

Normalized syntax for HTML elements and components

Let’s take a look at how HTML elements and Phoenix components are defined in EEx:

  <input style="padding: 1px">
  <%= live_component(@socket, Input, style: "padding: 1px") %>

The syntax is completely different. One is declarative and clean, the other is a function call inside a weird <%= ... %>.

Now let’s take a look at how HTML elements and Surface components are defined:

  <input style="padding: 1px">
  <Input style="padding: 1px">

Now both definitions are declarative, clean and use the same syntax. That makes the reading experience much more pleasant. I can also read it much faster, not only because there’s less noise but also because I don’t have to keep switching contexts (HTML ↔ EEx) all the time. This is only possible because we know that <Input> is a component. We didn’t’ lose that information so we can generate the necessary code to initialize it.

Syntactic sugar for attributes/properties

There’s an example of this feature in the “Getting Started” guide. I’ll just write a shorter version here to save us some time.

Imagine you want to create a button component that sets CSS classes based on the following
rules:

  • button - always set
  • is-loading - set if @loading is truthy

so assuminng @loading is true, the following code should be generated:

<button class="button is-loading">

if it’s false:

<button class="button">

Using Surface we can achieve what we want by just:

<button class={{ "button", isLoading: @loading }}>

Do you see how clean that code looks without any conditional or ugly string concatenation?

Now you can argue that we could achieve the same result with EEx by creating a function. Again, of course you can. After all, that’s exactly how it’s implemented under the hood.

We could also extend this very same concept to boolean attributes like disabled or readonly and create another function so we can handle those too. Something like:

<button class=<%= css_class(["button", isLoading: @loading]) %> <%= boolean_attr(:disabled, @disabled) %>>

Well, that works for sure. But I must confess that it makes my eyes bleed. Could Surface do any better? Let’s see:

<button class={{ "button", isLoading: @loading }} disabled={{ @disabled }}>

Doesn’t it look better? I truly believe it does.

Static checking

Grouping and traversing children

A parent component can classify its children in different logical groups and later traverse them and make decisions based on the information retrieved. They are not just dumb unstructured chunks of text. The concept of parent and child is not lost.

Tooling

  • Syntax highlighting - Since EEx allows you to create incomplete/invalid HTML code, it might get tricky to make syntax highlighting work properly when mixing HTML with EEx/Elixir code. Code written in Surface, on the other hand, is structured, predictable and validated at compile-time. It took me just a couple of hours to create a VS Code extension for it.

  • Auto-complete - Since information about components, properties and data (state assigns) are always available for introspection, it was trivial to add this feature to ElxirSense.

  • Documentation, Go-to-Definition and … a bunch of other related stuff around tooling.

Example of auto-complete/suggestions of assigns:

Example of auto-complete/suggestions of properties and directives:

I could keep going on and on, showing more benefits of the proposed abstraction and its positive impact on productivity and maintainability. I could also try to introduce some of the planned features like scoped styles or slots, but I’m afraid that, if I haven’t convinced you yet, keep trying is not going to make any difference.

BTW, it’s totally fine if you don’t see any value in the solution. As I mentioned before, choosing the write abstraction is hard and will depend heavily on the requirements of the project in hand. I don’t’ have any expectation that Surface or even LiveView will always be a good choice for all kinds of projects. There’s still a long way to go, lots of ideas to be validated and certainly many mistakes to be made. The one thing I believe is that keeping an open mind, trying to explore new ideas to improve existing solutions will always be beneficial to any ecosystem.

Cheers.

Malian

Malian

Hi folks!

Last week, Surface v0.3.0 has been released and it’s now available on hex.

This version improves the Surface Catalogue API which was previously released in v0.2.0 and also introduces a new surface compiler that allows autoloading colocated JS hooks.

Source code and installation instructions for the Surface Catalogue can be found at GitHub - surface-ui/surface_catalogue: An initial prototype of the Surface Catalogue · GitHub. If you want to see it in action, there’s a short video available at Marlus Saraiva on X: "Introducing the new Surface Catalogue. A first attempt to build something similar to Storybook for Surface and, hopefully, for any Phoenix/Liveview project in the near future. Prototype and installation instructions at https://t.co/rzden5u98g @phoenixframework #myelixirstatus https://t.co/xO2QHbmdqX" / X. The full changelog can also be found at surface/CHANGELOG.md at main · surface-ui/surface · GitHub.

We are happy to see that Surface is becoming more and more popular. There’s big a chance Surface is already part of many developers stacks, so it becomes essential to support these developers to have a stable version 1.0 of Surface.

Let’s not be afraid of words, our ambition is to make Surface the best possible platform for creating LV projects! To move forward on this path, we’re pleased to announce that @Malian and @miguel-s have joined our core team and will be helping us to improve Surface.

If you would like to shape the future with us, report issues or simply need help, feel free to join us on the slack channel or on github!

Happy coding!

msaraiva

msaraiva

Broadway Core Team

Hi folks!

Surface v0.1.0-alpha.2 has just been released with lots of bug fixes and new components. Here are the highlights:

Along with the new built-in components, there are also some new UI components available. For documentation and live examples see:

Source code can found at GitHub - surface-ui/surface_bulma: A set of simple Surface components based on Bulma · GitHub.

The Markdown component

The new <#Markdown> component allows users to write markdown content directly in a Surface template. The content will be validated and translated to HTML at compile-time.

Surface’s website was mostly written using this component. It’s very handy, especially if you want to mix static markdown and HTML content with runtime interactive components.

Example:

Reporting syntax errors:

If you’re using VS Code, there’s a new version of the Surface extension which adds syntax highlighting to the Markdown component’s content, as you can see in the examples above.

Have fun.

Where Next?

Popular in Announcing Top

OvermindDL1
I created a new library (rather I pulled out a couple files from my big project), it manages an operating system PID file for the BEAM. ...
New
pkrawat1
Presenting Aviacommerce, open source e-commerce platform in Elixir Aviacommerce is an open source e-commerce platform in Elixir. We at...
New
Crowdhailer
I have been updating a library that allows you to pipe between functions that use the erlang result tuple convention. Assuming you have ...
New
alisinabh
Hey everyone i’ve developed a library for Jalaali calendar for elixir which supports converting Gregorian dates to Jalaali and vice vers...
New
Eiji
ExApi is a library that I’m developing now and hope release soon This library will allow to: list all apis list all api implementation...
New
tmbb
I’ve been working on two packages (not on hex.pm yet) to build admin interfaces for phoenix apps: bureaucrat - which contains a bunch ...
New
MRdotB
I needed to reuse React components from my Chrome extension in my Phoenix/LiveView backend. I noticed that for Svelte/Vue, there are live...
New
Crowdhailer
Raxx is an alternative to Plug and is inspired by projects such as Rack(Ruby) and Ring(Clojure). 1.0-rc.1 is now available. To use it re...
New
type1fool
WebAuthnLiveComponent WebAuthnComponents See this post about renaming the package. Passwordless authentication for Phoenix LiveView app...
New
Azolo
Hey everyone, I just released WebSockex which is a Elixir WebSocket client. WebSockex strives to work as a OTP special process, be RFC6...
New

Other popular topics Top

Lily
In templates/appointment/index.html.eex: &lt;%= for appointment &lt;- @appointments do %&gt; &lt;tr&gt; &lt;td&gt;&lt;%= appoi...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 47930 226
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
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
Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 126479 1222
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

We're in Beta

About us Mission Statement