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

woylie
We are seeing a lot of warning logs like this: navigate event to "https://someurl" failed because you are redirecting across live_sessio...
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
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
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews