Skip to content

tolyo/nitroux

Repository files navigation

Nitroux

This library provides Nitrogen-like templating for your Plug applications.

Usage

Generate HTML

Each Nitroux function represents an HTML tag and generates HTML content:

iex> Nitroux.hr()
"<hr/>"

Add text

Each Nitroux function can accept text as a function parameter, allowing you to include text content within the generated tags:

iex> Nitroux.div("hello world")
"<div>hello wordl<div/>"

Add attributes

Each Nitroux function can accept keyword lists as function parameters. Each item in the list will be appended as an attribute to HTML. Hyphen-separated attributes should be passed as strings:

iex> Nitroux.div(class: "red", id: "1", 'data-model': "2")
"<div class=\"red\" id=\"1\" data-model=\"2\"><div/>"

Add HTML child tags

If html key is present, its value is treated as HTML content. html value can be a string, a Nitroux function, or a list thereof.

iex> Nitroux.div(html: p("hello world"))
"<div><p>hello world</p></div/>"

Use typed version

If you want additional type hints and don't mind additional verbosity, use Nitroux.HtmlTypedTags module. Instead of html key in keyword parameters, content is passed via a second parameter, which can be either a tag or a list of tags.

iex> Nitroux.HtmlTypedTags.div([class: "red"], Nitroux.HtmlTypedTags.p([], "hello world"))
"<div class=\"red\"><p>hello world</p></div/>"

Rationale

Take this HTML as an example:

<ul>
  <li class="tab-1">Tab1</li>
  <li class="tab-2">Tab2</li>
  <li class="tab-3">Tab3</li>
</ul>

We usually don't think of HTML as code, but if we were to treat it as such, we would have to admit that this example does not adhere to the DRY (Don't Repeat Yourself) principle. Nitroux solves this problem by allowing us to think of HTML as code, while keeping our maintenance burden to the minimum. The above example becomes:

  import Nitroux

  ul(
    1..3
    |> Enum.map(fn x ->
      li(
        class: "tab-#{x}",
        html: "Tab#{x}"
      )
    end)
  )

While the benefits of Nitroux might not be immediately apparent in this simple example, its value becomes evident when compared to the "no-js" approach, as currently proposed by the Phoenix framework through Phoenix.LiveComponent.

Imagine dealing with evolving business requirements that involve intricate conditional rendering logic, customization using a multitude of inline Tailwind CSS utility classes, sprinkled with numerous phx-hooks, all within non-standard HTML HEEx component functions. Additionally, frontend developers might contribute JavaScript code to integrate with third-party services. This complex mix can quickly lead to what's known as a "Big Ball of Mud" in your codebase.

Nitroux offers an alternative approach. Instead of reinventing HTML with a custom DSL, it encourages you to treat all HTML as pure Elixir functions. This approach assumes that you want to leverage your existing front-end tools while minimizing the abstraction layers between your Elixir models and the front-end. With Nitroux, you can bid farewell to .eex templates and eliminate the proliferation of empty _view files that often clutter Phoenix projects.

Nitroux is an ideal choice for scenarios involving Web Components, lightweight JavaScript frameworks like Alpine JS, HTMX, Stimulus, or comprehensive HTML/XML parsers like Owl or the now-deprecated AngularJS. It simplifies the development process and promotes cleaner, more maintainable code that even novice frontend developers can maintain.

For a starter template using Nitroux in a Phoenix Application, check out PHX-Boilerplate.

Installation

If available in Hex, the package can be installed by adding nitroux to your list of dependencies in mix.exs:

def deps do
  [
    {:nitroux, "~> 0.4"}
  ]
end

Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/nitroux.

About

Nitrogen-like templates for Elixir

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published