zachdaniel

zachdaniel

Creator of Ash

Tails - Tailwind & Tailwind Component Utilities

Making components take tailwind classes is a dicey proposition at best. You can’t just put a set of tailwind classes after another set and expect them to do the right thing, because later classes in the class string don’t override earlier ones, its all based on how “specific” the CSS that class applies. In looking for an example, I found a similar package for js that illustrates the need for it: https://www.npmjs.com/package/tailwind-merge.

I’m (slowly) building a set of utilities to help make more “tailwind-y” components, and also to be able to leverage tailwind in other ways. This library isn’t published to hex yet because it will need some more love, specifically it needs a lot more merge logic. It currently only handles some basic things.

Eventually, I could also see it supporting other kinds of directives to help overriding what a component does. For example, if a component sets something like bg-blue-500 hover:bg-blue-600, but you want it to use bg-red-500 always we could support something like <Component class="all_directives:bg-red-500" />. Or if you wanted to remove a class that the component adds, you could do so with <Component class="remove_class:bg-blue-500" />.

The ideas above are dubious, not sure if they are a good idea, but the point is that the potential for them is there :slight_smile: The part I am sure of is that having a class merger will allow us to write better components that can take tailwind classes and use them as overrides for their own classes.

It also handles merging a list, as well as conditional classes and nested lists, so in the end you might have something like this:

class={classes([
  "inline-flex items-center justify-center gap-2 text-sm font-medium font-sans transition-colors duration-300 disabled:cursor-not-allowed flex-grow-0",
  handle_button_hierarchy(@hierarchy), 
  handle_button_size(@size, @show_label),
  [
    "flex-row-reverse": slot_position == "trailing",
    "w-full": @expanded
  ],
  @class
])}

The other thing it currently does is defines functions that map to your tailwind colors, if configured with a tailwind.colors.json file to use. For those trying out LiveViewNative, this means you can reuse any custom tailwind colors, i.e <text color={primary_light_600()}>{@text}</text>. We could perhaps find other ways to make tailwind the “source of truth” that can be shared between web and LiveViewNative?

Curious to hear your thoughts! If we can get a few more people interested to help build out the class merging rules, and especially if we can make it more integrated with the tailwind config, that kind of thing.

https://github.com/zachdaniel/tails

Most Liked

trisolaran

trisolaran

Sounds definitely like something that could be useful. By the way, some of your ideas reminded me of this library: GitHub - cblavier/phx_component_helpers: Extensible Phoenix liveview components, without boilerplate · GitHub
which comes with utilities to manipulate CSS classes. Don’t know how similar they are to what you have in mind.

zachdaniel

zachdaniel

Creator of Ash

That does look very similar! My only qualm that I can see is that its just doing “prefix replacements”, which won’t work for things like block and hidden, and other tailwind specific things. But I do wonder if perhaps tails should just live inside of a tool like that :slight_smile: So they could say extend_class(..., tailwind: true)?

Last Post!

zachdaniel

zachdaniel

Creator of Ash

yeah, for me personally the ! operator isn’t a great solution because the consumer of the component has to know about more than it necessarily should. I.e with tails

# in this example the component provides `pb-1`
classes(["p-4", "pb-1"])
"px-4 pt-4 pb-1"

But with the prefixed removal method

# gotta thnk, which class do I want to remove from the child, and how to I reapply the "parts" that I care about
<component class="!p-4 px-4 pt-4 pb-1" />

Separately from that, the exclamation mark actually has meaning in tailwind. Granted, its meaning is to basically do what you’re saying so that might not matter?

Where Next?

Popular in Announcing Top

KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36820 110
New
OvermindDL1
I created a new library (rather I pulled out a couple files from my big project), it manages an operating system PID file for the BEAM. ...
New
versilov
Could not wait for the missing Elixir ML libraries to appear, so, I wrote one myself, taking https://github.com/sdwolfz/exlearn as a foun...
New
mindok
What is ContEx? A pure Elixir server-side data plotting/charting library outputting SVG. It has nice barcharts in particular and works g...
New
Qqwy
TypeCheck: Fast and flexible runtime type-checking for your Elixir projects. Core ideas Type- and function specifications are const...
336 14774 100
New
trisolaran
Hi! :waving_hand: I would like to present LiveSelect, a little library that I wrote to easily add a dynamic selection input to your LV f...
198 11283 107
New
martinthenth
Hello everybody :wave: Recently, some of my colleagues talked about database ids and uuids and their problems, and I remembered the pain...
New

Other popular topics Top

electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 31586 112
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
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

We're in Beta

About us Mission Statement