bartblast

bartblast

Creator of Hologram

Hey! For those following Hologram’s progress… I’m excited to share that I’ve just published the official roadmap for Hologram. You can check it out at: https://hologram.page/docs/roadmap

The roadmap page provides a comprehensive overview of:

  • Development Plan: Featuring both immediate priorities (before ElixirConf 2025) and medium-term goals (after ElixirConf), with features listed in planned order of implementation

  • Feature Status: Detailed breakdown of what’s already implemented and what’s coming next

My immediate focus is on key improvements like optimizing client bitstring performance, implementing component-level rerendering, completing DOM events support, and adding cookies and sessions functionality.

The page also includes detailed status tables for various framework components, including the template engine, framework runtime, and Elixir client runtime features.

I hope this transparency helps the community understand where Hologram is headed and what to expect in the coming months. I welcome your feedback and contributions!

What features are you most excited about? Let me know in the comments!

Showing Posts 1 to 10

D4no0

D4no0

Congrats! Very nice progress!

Eiji

Eiji

I guess it’s rather obvious that rest of the documentation pages are also high priority:


  • Non-Command Action Triggers - Enable triggering actions from server code outside of commands.

I guess something like Non-Command Command Triggers - Enable triggering command from server code outside of commands would be done within Component Subscription DSL, right?


I don’t plan to support Vue-like directives at the moment. I think Svelte-like blocks are much more readable and maintainable than Vue-like ones, especially in longer or nested structures. The current approach with {%if condition}...{/if} and {%for item <- items}...{/for} blocks provides a cleaner template structure IMO, but I’m open to discussion of course.

I would like to use both:

  1. Svelte-like blocks for conditionally adding many elements
  2. Vue-like directives for a single element especially if it’s short

For example:

{%if some_condition}
  <div>
    …
  </div>
  <div :if={other_condition}>
    …
  </div>
  <div>
    …
  </div>
{/if}

See also for example:

{%for item <- items}
  {%if some_condition}
    <div>
      …
    </div>
  {/if}
{/for}
<!-- vs -->
<div :for={element <- elements} :if={some_condition}>
  …
</div>

This adds 4 extra LOC and 2 extra levels of indentation, so what’s “clear” depends on context. Block conditions are much more helpful to work with multiple elements, but they are too much for a single element.


If you need to colocate multiple components, you can use nested modules:

Creating a module for just one function is overcomplicated. Phoenix supports both live_component/1 and functions components, and they are used in completely different cases (short template vs standalone process with it’s own event handling).

Simply think that some library have tons of components and want to support both Hologram and Phoenix. In fact you require to split 1 or few modules into tens of modules, so each even smallest element like button have it’s own module and the developer have to scroll the documentation to skip tens of entries in the sidebar. This way folks would start to ask ex_doc team to add another tab like MIX TASKS, but for Hologram templates.

Also think about phx_new as right now we need a 1:1 copy with just a bit different template syntax. Does it make sense to copy-paste all of the logic of each generator published on hex? Of course we can ask maintainers to do that for us, but I’m not sure if all of them would agree to double overall template if they even reply.


Support for Phoenix templates

Just think that every project and every library on hex that uses Phoenix templates needs to be rewritten to support Hologram not because the logic changes, but because it uses different syntax or something only different sigil. It’s like Linux vs Windows - sure, Linux have many native games, but it’s still better to optionally support Windows, right?

I believe that such thing would definitely speed up Hologram adoption. Just think that all default Phoenix templates and generators would be supported out-of-the-box by Hologram. For sure it’s not #1 must have, but something I would definitely like to see before 1.0.0 release.


Configuration to minify HTML. The extra spaces may impact on element styles and some selectors to fail:

<div>
  {%if some_condition}
    What if condition fails? We have extra spaces here!
  {/if}
</div>

If remember correctly you have also mentioned some client-side database and sync. I guess it’s a very long term thing, but I would definitely wait for it. It would be nice to add a simple Save cache function and in a simple action tell Hologram to cache templates and sync database, so the client can work offline.


  • Prop Watchers - Add the ability to react to prop changes with state updates.

What’s the use-case for it? Can’t we just call put_something function call put_state and do something extra?


Unfortunately for my use cases I would need to wait few months for some changes, but the priority list is clear and looks very interesting. :+1:

jam

jam

Looking good! Thanks for sharing.

JS Interop

Curious what this might look like.

Component Subscription DSL

This definitely caught my attention. Would be interested to learn more.

I think Svelte-like blocks are much more readable and maintainable than Vue-like ones

fwiw, I agree. I also think that supporting both would be more confusing.

Eiji

Eiji

I don’t think so as long as they would be well documented as an alternatives to each other. They are indeed much more readable, but with a good syntax highlight it’s not really a big deal. However they took extra lines and indentation levels which makes them verbose.

On one side Vue-like attributes are better for single elements, but adding same attribute to many elements is bad as same as wrapping elements with this attribute in one parent container.. However in opposite Svelte-like blocks are much better for multiple elements, but they are a bit annoying to use on single elements.

For example imagine that you create a menu and every even element have an if (so you cannot group them in one block - again for example). This gives us 2 LOC * number of even elements. In Vue-like syntax I focus on the elements and in Svelte-like syntax I focus on the blocks and both would be fine if they would be used for their purposes.

How does it look

{%if some_condition}
  <div>
    …
  </div>
{/if}
<div>
  …
</div>
{%if some_condition}
  <div>
    …
  </div>
{/if}
<div>
  …
</div>
{%if some_condition}
  <div>
    …
  </div>
{/if}
<div>
  …
</div>
{%if some_condition}
  <div>
    …
  </div>
{/if}
<div>
  …
</div>
{%if some_condition}
  <div>
    …
  </div>
{/if}
<div>
  …
</div>

comparing to:

<div :if={some_condition}>
  …
</div>
<div>
  …
</div>
<div :if={some_condition}>
  …
</div>
<div>
  …
</div>
<div :if={some_condition}>
  …
</div>
<div>
  …
</div>
<div :if={some_condition}>
  …
</div>
<div>
  …
</div>
<div :if={some_condition}>
  …
</div>
<div>
  …
</div>
bartblast

bartblast OP

Creator of Hologram

Looping everyone in: @Eiji quotes fragments of a discussion we had in a GitHub issue: Missing or undocumented features when adding Hologram support to existing LiveView app · Issue #181 · bartblast/hologram · GitHub

Correct.

These are two separate things - in some scenarios we may need to just trigger an action for a single connection (window tab) without having to define a subscription in a component. The DSL would be for channel-like scenarios where we want to send to specific topics (e.g. chat scenario). What are your thoughts in this regard?

I agree with @jam - this would be confusing if we supported both.

I don’t reject the idea of introducing some simple syntax for partials eventually, but not in the medium-term.

Can you elaborate on that?

Browsers collapse sequences of whitespace into a single space when rendering text content. For block elements, whitespace at the beginning and end of content is ignored entirely. In normal text flow, no matter how many spaces, tabs, or line breaks you have between words, they’ll render as a single space. There are specific exceptions to this, but in such rare cases (like <pre> elements) you can just write the if block without surrounding whitespaces.

Minifying whitespace text nodes makes sense, though, in my opinion.

At the moment there is no way to react to prop changes. The only things that can change the state are actions that react to DOM events, other actions, or commands.

Example use case is described here: How to modify component state in reaction to a prop change? · Issue #161 · bartblast/hologram · GitHub

bartblast

bartblast OP

Creator of Hologram

Regarding Phoenix template support - I understand that compatibility with Phoenix templates would certainly ease adoption and reduce the migration burden for developers looking to try Hologram. It’s a thoughtful suggestion that I’ve considered carefully.

However, after weighing the tradeoffs, I’ve decided not to pursue Phoenix template compatibility for several important reasons:

  1. Divergent Design Philosophies: Hologram and Phoenix have fundamentally different approaches to UI rendering. Hologram is designed for client-side rendering with Elixir-to-JavaScript transpilation, while Phoenix templates are server-rendered. Supporting both could create conceptual inconsistencies and may confuse developers (point 3).

  2. Maintenance Burden: Supporting two template syntaxes means maintaining two parallel systems, doubling the work for every feature, bug fix, and optimization. This could significantly slow down Hologram’s development.

  3. Confusing Developer Experience: Offering two ways to do the same thing can create decision fatigue and confusion for developers. New users might struggle to understand which approach to use when.

  4. Diluted Innovation: By trying to maintain compatibility with Phoenix templates, we might constrain Hologram’s ability to innovate in ways that are optimized for client-side rendering patterns.

  5. Optimization Challenges: Hologram’s template system is optimized for its specific transpilation approach (and will be optimized even more). Phoenix templates might not transpile as efficiently to JavaScript, potentially leading to performance issues.

  6. Documentation Complexity: Having to document two parallel systems would make the documentation more complex and potentially harder to navigate.

  7. Testing Overhead: We’d need to test all features across both template systems, increasing the testing burden.

  8. Divergent Evolution: As Phoenix continues to evolve its template system, maintaining compatibility would become increasingly difficult over time.

  9. Mixed Paradigms: Phoenix templates are designed with server-side rendering in mind, while Hologram templates are designed for client-side rendering. These different paradigms might lead to subtle bugs or unexpected behaviors when mixing approaches.

  10. Clear Differentiation: Having a distinct template syntax helps clearly position Hologram as a different approach to UI development in Elixir, rather than just an alternative to Phoenix LiveView.

  11. Focus on Core Strengths: By focusing exclusively on own template system, we can ensure it’s the best it can be, rather than dividing resources between two systems.

  12. Migration Path vs. Compatibility: Instead of supporting Phoenix templates directly, we could focus on providing clear migration paths and tools to help developers transition from Phoenix to Hologram.

I believe that maintaining a focused, single-template approach will ultimately lead to a better developer experience and a stronger framework in the long run. That said, I’m committed to providing clear migration paths and documentation to help Phoenix developers transition to Hologram as smoothly as possible.

bartblast

bartblast OP

Creator of Hologram

Regarding the syntax discussion (Svelte vs Vue style), I appreciate your thoughts on this, @Eiji. While Vue’s attribute-based syntax is indeed concise, I believe we should prioritize maintainability and readability over brevity.

Code is written once but read many times by different developers. When quickly scanning through a component to understand its structure and logic, block-style syntax provides clearer visual cues about the control flow:

{%for item <- items}
  {%if some_condition}
    <div>
      …
    </div>
  {/if}
{/for}

This approach makes it immediately obvious where loops and conditionals begin and end, especially in complex nested structures. Compare this to the attribute-based approach:

<div :for={element <- elements} :if={some_condition}>
  …
</div>

You’re right that Vue-like attributes can be more elegant for single elements, while Svelte-like blocks work better for wrapping multiple elements. However, for Hologram specifically, there are several reasons why a Svelte-inspired block syntax makes more sense in my opinion:

  1. Complex component logic: As Hologram components grow to handle more complex UI logic, the block syntax scales better visually, making the relationship between nested conditions and loops more explicit.

  2. Debugging and maintenance: When troubleshooting components, having explicit opening and closing tags for control structures makes it easier to identify where issues might be occurring.

  3. Learning curve: For developers new to Hologram, block syntax provides clearer visual indicators of the component’s structure, making it easier to understand how the UI is being constructed.

  4. Separation of concerns: Block syntax creates a clearer separation between structural elements and control flow logic, which can lead to more organized and readable components.

  5. Consistency: Supporting both syntaxes simultaneously would likely confuse users and create inconsistency across codebases. Having a single, well-defined approach makes the framework more approachable and reduces cognitive load when switching between projects.

While I acknowledge your point about good syntax highlighting mitigating some readability concerns, the fundamental structure still matters when reviewing code across different environments or when dealing with increasingly complex components.

The block-style approach aligns with Hologram’s goal of creating maintainable, readable UIs that can scale with application complexity while remaining approachable for developers at all experience levels.

bartblast

bartblast OP

Creator of Hologram

Thanks @jam! At this stage, I don’t have detailed specifications for the JS Interop and Component Subscription DSL features - just some initial ideas I’m exploring. Once I get closer to implementing these specific features, I’ll likely open dedicated discussions to gather community input and share my thoughts in more detail.

I appreciate your feedback on the template syntax approach too! Looking forward to sharing more as the project progresses.

Eiji

Eiji

Yes, they are different. That’s why I used your naming to name call it Non-Command Command Triggers instead of Non-Command Action Triggers.

defmodule MyLib do
  def on_something_asnyc(pid) do
    Hologram.trigger_command(pid, :command_name)
  end
end

defmodule MyApp.Page do
  # …

  def init(_params, component, _server) do
    pid = self()

    spawn(fn ->
      # non-prod code - just for example …
      Process.sleep(1000)
      MyLib.on_something_asnyc(pid)
    end)

    component
  end

  def command(:command_name, params, server) do
    IO.puts "Triggered from MyLib"
    server
  end
end

Wait, so Phoenix syntax in heex is confusing too?

<%= if some_condition do %>
  <div :if={other_condition}>…</div>
  …
<% else %>
  …
<% end %>

I’ve used both really often and never found them confusing …

Oh, no need if you don’t plan to support Phoenix templates.

I’m aware that they are seen as single space. I wanted to say that there should be no space at all due to how CSS works. Element with “just one space” is not considered empty.

Selectors 4 now redefines :empty to include elements that contain only whitespace. This was originally proposed as a separate pseudo-class :blank but was recently retconned into :empty after it was determined that it was safe to do so without too many sites depending on the original behavior. Browsers will need to update their implementations of :empty in order to conform to Selectors 4. If you need to support older browsers, you will have to go through the hassle of marking elements containing only whitespace or pruning the whitespace before or after the fact.

There are just many cases where we don’t want extra space (no matter how much) - not even mentioning that templates would be a bit smaller.

Exactly, so if everything happens in action/command then we can do it without any extra API:

defp put_options(component, options) do
  value = if component.state.value in options, do: value, else: @default_value
  put_state(component, options: options, value: value)
end

Did I missed something? I do not see special watcher for options really necessary if we can just use such a simple function …

Oh, I expected it as simple as:

# hologram clause for render_template/1 goes here …

def render_template(%Phoenix.LiveView.Rendered{} = rendered) do
  rendered
  |> rendered_to_raw()
  |> render_template()
end

# raw i.e. safe HTML clause …
def render_template({:safe, html}) do
  # …
end

Does it cause a lot of problem for you?

Oh, not really if you use IO.warn/1 to let user know that templates are converted to raw HTML and to use all Hologram feature developer have to rewrite it later i.e. when there would be a need for it.

…

# raw i.e. safe HTML clause …
def render_template({:safe, html}) do
  # use proper message at here
  IO.warn "Rendering raw HTLM …"
  # …
end

Look at example above. It’s not about supporting all of the live stuff - just render template with it’s assigns as raw HTML.

Maybe I’m wrong with something, but supporting only template (without all live stuff) would be easy to test, no? It’s just about if assigns are part of the raw HTML or not. Again, maybe I see it too plain …

No for a backwards-compatibility i.e. until 2.0.0 version they should not change the Rendered struct.

Yes and that’s what you should let developer know in IO.warn/1 call. The raw HTML would be like a string value added to state.

Oh, I really appreciate your decision, but just sometimes I feel like I’m from another world. People say it’s confusing and I used that in Phoenix and never considered it like you. I just understand all other points except said confusion. If I would say what’s more confusing from my perspective is to not support a short syntax since a mature framework like Phoenix supports both, but maybe it’s just me …

Hmm … For me a good practice is to use :if and :for at the end of the element and if the element is too long then each attribute is on it’s own line. Maybe that’s why I never saw it confusing … :thinking:

<!-- Looking here: no if/for blocks found -->
<div class="this-element-is-way-too-long-for-a-single-line"
  data-key="value"
  …
  :for={element <- elements}
  :if={some_condition}>
  <!-- Looking at last attributes: found :if and :for -->
  …
</div>

I guess you address something like:

<!-- Looking here: no if/for blocks found -->
<div class="this-element-is-way-too-long-for-a-single-line" data-some-key="some-value" … :for={element <- elements} :if={some_condition}>
  <!-- Is that your confusion? -->
  …
</div>

I would say it’s rather something that a formatter should worry about, no? Or have I missed something else?

Just for sure - I’m not commenting your decision - I replied only to the confusion part. I clearly don’t see something you do, sorry …

KP123

KP123

Would a syntax like Temple be possible for what you have in mind?

Where Next? Top

Trending in News & Updates Top

sorenone
Today we’re releasing Oban for Python. Not an Oban client in Python. Not a pythonx wrapper embedded in Elixir. Nope, it’s a fully operati...
New
bartblast
I’ll be using this thread to share Hologram patch release announcements. Minor releases will continue to get dedicated threads with blog ...
New
sorenone
This release unifies configuration for queues, repos, and services, swaps opaque timing integers for readable durations, and backports pe...
New
pcharbon
:heart::heart::heart::heart::heart::heart::heart::heart::heart::heart::heart::heart::heart::heart::heart::heart::heart::heart::heart::hea...
New
jvoegele
Bond brings Design by Contract to Elixir: preconditions, postconditions and invariants as executable specifications, checked at runtime a...
New

Other Trending Topics Top

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
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews