zachdaniel

zachdaniel

Creator of Ash

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

Showing Posts 1 to 9

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 OP

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)?

cblavier

cblavier

We actually no longer do prefix-based replacement in phx_component_helpers :slight_smile:

extend_class instead switched to a declarative mode where you can use a bang​:red_exclamation_mark:operator to remove default classes, such as:

<.button class="!m-* m-12 !hidden block"/> 

to override default margin and display properties.

I once opened a topic on this specific issue here: Need help with an issue on my phx_component_helpers library

Sebb

Sebb

stupid question: how does this work at all? Doesn’t the tailwind compiler just deliver the CSS for the classes it sees at buildtime? So when the only tailwind class in my templates is text-sm and I dynamically add text-xl how can the tailwind compiler know about that…?

cblavier

cblavier

The tailwind CLI will only scan your source code to see what CSS classes should be bundled in the output css.

So the only risk is to get, in your bundled CSS, classes that you actually won’t use because they have been dynamically excluded.

(I replied for my own lib I didn’t looked into Tails)

Sebb

Sebb

So it does not parse the HTML and looks in @class but just looks for the classes as text in all files?

What about

size = "xl"
class = "text-#{size}"

can’t work, right?

cblavier

cblavier

You’re right it can’t work. You should never use String concatenation with tailwind

zachdaniel

zachdaniel OP

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?

— All posts loaded —

Where Next? Top

Trending in Announcing Top

wojtekmach
Hey everyone! Req is an HTTP client for Elixir that I’ve been working on for quite some time. There is already a lot of HTTP clients out...
New
handnot2
Samly can be used to enable SAML 2.0 Single Sign On in a Plug/Phoenix application. This library uses Erlang esaml to provide plug enabl...
New
woylie
Flop is an Elixir library that applies filtering, ordering and pagination parameters to your Ecto queries. offset-based pagination with...
New
restlessronin
The repo is at GitHub - cyberchitta/openai_ex: Community maintained Elixir library for OpenAI API · GitHub. Docs are at OpenaiEx User Gu...
152 11030 135
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
fuelen
Hi all! I want to present a small library which provides a mix task for generating an Entity-Relationship Diagram for Ecto schemas. You...
New
woylie
Phoenix components for pagination, sortable tables and filter forms with Flop and (optionally) Ecto. pagination cursor pagination sorta...
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
mudasobwa
I am seeing a lot of aplications of Argumentum ad Vericundiam in software discussions. They do link some piece of writing and point us to...
New
bartblast
Hey folks, I just published a post about Hologram’s funding and where the project goes next - the short version: Curiosum as Main Spons...
New
sorenone
Today we’re releasing Oban for Python. Not an Oban client in Python. Not a pythonx wrapper embedded in Elixir. Nope, it’s a fully operati...
New
Herve37
We’re evaluating API mocking tools for OpenAPI-based projects and would love to hear what other teams are using. We’re particularly inte...
New
sergio
It’s not that it’s vocabulary is too advanced. It’s something worse. I get lost trying to follow even a paragraph written by Claude. It’...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews