mssantosdev

mssantosdev

Combining HTML classes with initial values in Phoenix Components

Hey, everyone.

I’ve been working with Phoenix Components for a few weeks, and they are great. One thing I use a lot when building custom components is the global attribute with default values set. It’s a good option for building reusable elements without repeating stuff every time.

However, I’ve noticed a “pattern” when creating components with class modifiers.

Suppose I have a <.paragraph />:

attr :rest, :global, default: %{class: "paragraph"}
slot :inner_block, required: true

def paragraph(assigns) do
  ~H"""
  <p {@rest}><%= render_slot(@inner_block) %></p>
  """
end
<.paragraph>My paragraph</.paragraph>
<p class="paragraph">My paragraph</p>

The problem is that I have modifiers for my paragraph, like paragraph--medium, paragraph--small, or even other types of classes like is-hidden, is-animateable etc. To use them, I need to repeat its base class.

<.paragraph class="paragraph paragraph--with-modifier">
  This is a paragraph with a modifier
</.paragraph>
<p class="paragraph paragraph--with-modifier">My paragraph</p>

Of course, changing how things currently work because I don’t want to repeat a class is not a good idea, and I understand the default value is not the best option for what I’m trying to do. But things can get more complex as we have more than a single base class.

Also, I don’t think creating additional components to consider all the modifiers they could have is a good idea. It’s just simpler to use classes.

Now, to the suggestion: what if we had something like an initial property for the class in global attributes? Values from it would be combined with the values passed to the component automatically.

attr :rest, :global, initial: %{class: "paragraph is-animateable is-i-dont-know"}
slot :inner_block, required: true

def paragraph(assigns) do
  ~H"""
  <p {@rest}><%= render_slot(@inner_block) %></p>
  """
end
<.paragraph class="paragraph--with-modifier">
  This is my paragraph with modifiers
</.paragraph>
<p class="paragraph is-animateable is-i-dont-know paragraph--with-modifier">This is my paragraph with modifier</p>

I read this article, which is a great workaround, but maybe we can improve it.

What do you all think?

Thanks!

Most Liked

LostKobrakai

LostKobrakai

Ah, didn’t look at that one. I wouldn’t consider this a workaround. That’s imo the business logic of your component. Sure initial_value sounds easy, but you can compose passed data with defaults in multiple ways, not just one. How would you decide if the syntax you showed combines values or replaces the default or does some more complex transformation? Even combining values is not a trivial assumption to make, as it might work well for classes or styles, but unlikely for much else.

aiwaiwa

aiwaiwa

{@rest} could be tweaked inside the render before returning ~H""" like is done in core_components:


  def input(%{type: "checkbox", value: value} = assigns) do
    assigns =
      assign_new(assigns, :checked, fn -> Phoenix.HTML.Form.normalize_value("checkbox", value) end)

to tweak the list of classes based on availability of another class.

Where Next?

Popular in Proposals: Ideas Top

azyzz228
The slow network is known to be an Achilles heel of LiveView’s architecture. Recently, I was working on creating a fast rendering map wi...
New
snofang
In a typical business development task, having a function in a context module which accepts attributes of map type and passes them to Ect...
New
GenericJam
I’ve been messing around with image generation models recently and thought this could be wrapped in a library or people could just use th...
New
mikesax
On a Rails/Turbo site, the first page is typically loaded using http GET and then sockets are used navigate and replace HTML content for ...
New
virinchi_cv
The Problem Phoenix 1.8 comes aggressively coupled with Daisy UI, a decision which many developers in the community have had mixed feelin...
New
cevado
IEx is a very powerfull shell and it would be awesome to have all this power integrated inside a code editor. Clojure enables something l...
New
sevensidedmarble
All the pieces are there to execute arbitrary JS commands from the server. You can put them on a data property and call them from the cli...
New
derekkraan
I have been using a multi-endpoint setup in my app, just because I think it makes the most sense for a multi-subdomain app. This worked w...
New
davydog187
I’ve been enjoying the new Streams API, but I keep needing to work around the lack of access to the underlying items. One issue that cons...
New
superchris
Currently there is no out of the box way to support DOM Custom Events in phoenix. I’ve created a separate library to do this, but I’d lov...
New

Other popular topics Top

WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 43657 311
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New

We're in Beta

About us Mission Statement