dstockdale

dstockdale

Separate stying of heex templates like stylesheets for components?

Just pondering here but is there some conceivable way to one day separate the core markup of components and what styles them?

I know that’s currently not possible, but I’m just wondering if it could be viable.

Here’s an example of what I mean. I don’t love the classes that core_components.ex comes with and sure I can go through and customize this file to hearts content but I’d sort of prefer to do things in a different and perhaps more reusable way.

e.g.

def simple_form(assigns) do
 ~H"""
    <.form :let={f} for={@for} as={@as} {@rest}>
      <div class="mt-10 space-y-8 bg-white">
        <%= render_slot(@inner_block, f) %>
        <div :for={action <- @actions} class="mt-2 flex items-center justify-between gap-6">
          <%= render_slot(action, f) %>
        </div>
      </div>
    </.form>
  """
end

So I can pass a class="special-class" to my <.simple_form tag but it still comes with 2 places that have static classes that I might not like.

What I’d love to somehow be able to do is something akin to stylesheets but also not exactly. I had a weird idea that it might be possible to merge heex markup together so one part could be completely unstyled or ‘headless’ as it’s sometimes referred to.

For instance I like Doggo’s style. It’a great collection of useful headless components that focus of accessibility. That’s great, but I’d still like to have a way of making them my own beyond just passing class attributes or copying and editing the components.

e.g. from Doggo

def action_bar(assigns) do
  ~H"""
    <div role="toolbar" class={["action-bar" | List.wrap(@class)]} {@rest}>
      <button :for={item <- @item} phx-click={item.on_click} title={item.label}>
        <%= render_slot(item) %>
      </button>
    </div>
  """
end

Here I can add a class for the wrapping div but I can’t directly access the button within.

./core_components.ex

defmodule ExampleWeb.CoreComponents do
  # My imaginary macro for applying styles
  use ComponentStyling, :default_styles

  # Pinching Doggo's action_bar as a simple example
  def action_bar(assigns) do
  ~H"""
    <div role="toolbar">
      <button :for={item <- @item} phx-click={item.on_click} title={item.label}>
        <%= render_slot(item) %>
      </button>
    </div>
  """
  end

./default_styles.ex

defmodule ExampleWeb.DefaultStyles do
  ...
  # Matching function contains `<style:elem` tags applying applying 
  # things like classes to the heex template
  def action_bar(assigns) do
  ~H"""
    <style:div class="nav-default">
      <syle:button class="bg-blue-500 hover:bg-pink-500 etc" />
    </style:div>
  """
  end

I’m just making stuff up here to get a point across and many might think it’s a terrible idea but I think it would make working with heex templates quite interesting. Libraries like Doggo could evolve and ship with default styles that people could every easily style themselves.

Of course styling with <style:div could be very laborious (it’s just an idea iac) but I’d imagine doing a generator would make sense mix phx.styles custom_components custom_style. This would read your heex templates from custom_components.ex and export matching <style:etc ones

After this long imaginative discourse on what I was thinking about my actual question is is there a way or how would you approach being able to merge heex templates or is that just a terrible idea?

Most Liked

Hermanverschooten

Hermanverschooten

Not an answer to your question, but aren’t you reinventing the wheel?
CSS was made for what you want to do.
Moreover I feel most people treat the CoreComponents as a gospel to follow, while I think it was more meant to be example code.
You should adapt this to your needs, or even throw it away and make something else if it doesn’t suit your needs.

Going back to your question, you could probably create a new sigil that would allow you to precompile your version to heex.

eahanson

eahanson

+1

Because I like to be in complete control of the app that I’m going to have to maintain for (hopefully) years, the first thing I do in a new Phoenix app is comment out CoreComponents. When I need a component that it provides, I copy just that component into a module that I created (for example, I’ll typically have a Table module with a bunch of table-related components) and then make whatever changes are needed for my particular use case.

(One of the changes that I make is to replace Tailwind with CSS. I mention this here because I see a lot of people use Tailwind thinking that it’s the new widely accepted default and I want everyone to know that some people intentionally avoid Tailwind.)

Where Next?

Popular in Discussions Top

andre1sk
A big advantage to Elixir is all the distributed goodness but for many applications running on multiple nodes having integrated Etcd, Zoo...
New
blackode
Elixir Upgrading is so Simple in Ubuntu and It worked for me Ubuntu 16.04 git clone https://github.com/elixir-lang/elixir.git cd elixir...
New
AstonJ
Please see the new poll here: Which code editor or IDE do you use? (Poll) (2022 Edition) It’s been a while since we first asked this, I...
208 31265 143
New
AstonJ
Are there any Elixir or Erlang libraries that help with this? I’ve been thinking how streaming services like twitch have exploded recentl...
New
Crowdhailer
I’ve been hearing much about the new formatter and it’s something I have been keen to try. I find examples buy far the most illuminating...
248 19327 150
New
mbenatti
Following https://github.com/tbrand/which_is_the_fastest |&gt; https://raw.githubusercontent.com/tbrand/which_is_the_fastest/master/imgs...
New
RudManusachi
What configs will make sense to put to runtime.exs? – A bit of how I configure apps: I have generic configs in config/config.exs, dev...
New
ben-pr-p
In general I’ve been sticking to this community style guide GitHub - christopheradams/elixir_style_guide: A community driven style guide ...
New
Qqwy
Looking at the stacks that existing large companies have used, WhatsApp internally uses Mnesia to store the messages, while Discord uses ...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

Other popular topics Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a &gt; b) do {:ok, "a"} end if (a &lt; b) do {:ok, b} end if (a == b) do {:ok, "equa...
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
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
AstonJ
Please see the new poll here: Which code editor or IDE do you use? (Poll) (2022 Edition) It’s been a while since we first asked this, I...
208 31265 143
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 52673 488
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
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement