mssantosdev

mssantosdev

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!

Showing Posts 1 to 5

LostKobrakai

LostKobrakai

attr :class, :string
attr :rest, :global
slot :inner_block, required: true

def paragraph(assigns) do
  ~H"""
  <p class={["paragraph is-animateable is-i-dont-know", @class]} {@rest}>
    <%= render_slot(@inner_block) %>
  </p>
  """
end
mssantosdev

mssantosdev OP

I mentioned your solution in the post, @LostKobrakai.

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.

mssantosdev

mssantosdev OP

I agree. There are multiple ways we can accomplish that. My point is: should we have something out-of-the-box for this case?

Yes. Classes/styles/data-attributes are probably the only use-cases for this as they can have multiple values.

— All posts loaded —

Where Next? Top

Trending in Proposals: Ideas Top

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
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
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews