pepicrft
Styled components in Phoenix?
Hi ![]()
I would like to implement a solution like styled-components for Phoenix components such that developers can write their styles using Elixir and the CSS would be generated at compile time. The API would be something along the lines of:
defmodule Components do
use Phoenix.Component
style background_color: "red"
def my_component() do
~H"""
<div class={@styled_class}>
Hello world
</div>
"""
end
end
Because I relatively new to Elixir macros and the compilation process, I’m struggling to map the API to an actual implementation. I was thinking about making style a macro that uses module attributes to store the styles of the components, similar to how attr does, and then have a custom compiler that combines the styles for all the components in the project and outputs a CSS into a configured path.
One piece I don’t know how to do without a sigil that wraps ~H is passing the @styled_class assign. I was thinking about style writing an attr attribute that uses the default: as a way to set the actual value.
Do you think the implementation is sensible? If not, what would you do differently?
I know Tailwind is proposed as the default in Phoenix, but I’m not a huge fan of its mental models so I’m exploring a solution that align with my mental models.
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #performance
- #security











First 8 of 8 Posts
fceruti
Hey Pedro,
I’ve been working on a somewhat similar solution to what you are proposing here. I was planning on open sourcing it once it was a little bit more polished, but the intention from the beginning was to open source it. I’m open on giving access to interested parties now.
The basic architecture is composed of 3 parts: Components, Nomenclators & Hydrators.
Components
Components are a super set of phoenix components with two additional macros:
variantandclasses(well, alsocomponent, I couldn’t overridedef, as phoenix already does that).These two macros are used to describe how the component can change depending on either code calls aka,
size={:sm}or what class name are to be used for an inner element. Which brings me to the next partNomenclators
Nomenclators responsability is to give class names to components and it’s sub elements.
This is the default nomenclator, that spits classes like
btn btn-sm btn-outline btn-primary. If you check out the code, class_name/3 can be either_component, _variant, _option, used to variant class names or_component, :classes, _class_namethat gives names toclassesmacros defined in the component.You can see how just with this, you could just add tailwind inline classes and forget about the next part:
Hydrators
Hydrators responsability is to Hydrate with css the skeleton that nomenclators create. They are auto generated based on: the apps it should go look for components, the parent hydrator and a nomenclator.
This is a very early stage of the
DefaultHydratorthat users will be able to use as a base.Next is the auto generated version of a hydrator that has
DefaultHydratoras it’s parent.A few things to note here:
Finally there are a few mix tasks to generate all the files.
Right now I’m working on two things:
There are more things about this library, but that’s the gist. Oh, and it’s called
BuenaVista.Let me know if you’d interested in collaborating
pepicrft
Hey @fceruti
First of all, I love the name
— It’s awesome to see there’s more thinking going into improving the state of the art of in-code styling. There are some similarities with how I was envisioning this library, so let me share the ideas that I had to see if it’d make sense to collaborate (and maybe converge them?) or rather have two different solutions to address similar needs.
And that’s pretty much it:
Do you think these are ideas that we can converge?
fceruti
This is actually the main motivation for this library. This is how you’d configure themes in your project.
Note that you can define a parent Hydrator and only modify it’s variables, pretty much what I quickly saw from theme-ui.
You can create break point variable and use it directly in the theme
Yup
I hadn’t thought about this, but it’s completely possible as it only touches the
BuenaVista.Componentmodule and it’s macros. It could be an argument for thevariantmacro, if you expect this to be a class name variant or an attribute one. This also opens the possibility to other html attributes.PS: This is an example of the generated CSS (the actual css is rubbish ATM)
fceruti
Yeah, I like it too. I even bought buenavista.dev.
Sure, there are many design decisions that shape this kind of tool. It would be awesome to pool resources, but I totally get if the kind of decision I made don’t make sense to you. Having said that, I really just want to have a library that makes is a contribution to the community, and in my wildest dreams, a reason why people choose Elixir/Phoenix over other language/framework combo.
I’m not particularly invested in the implementation.
cmo
CVA does something similar.
benlime
The CVA approach is a little bit more barebones / minimal.
Have been using styled components based approaches a lot in react-based apps but since I rarely found the need for it anymore since using utility based classes (like tailwind).
I’d be happy if you give it a try.
pepicrft
I can’t commit much time to it but let me know how I could help with the project
fceruti
That’s great, even as a second pair of critical eyes, would be of great benefits. I’ll dm you this week.
Btw, the same invitation goes to anyone interested.