About
Author and maintainer: David Sancho (opens in a new tab)
Motivation
There are a few reasons why this project exists and why it came to live.
There was a need
In my experience, writing React with a CSS-in-JS library is one of the best combos for writing scalable design systems, UI libraries and applications. When I discovered Reason back in the day (around 2018), it wasn't possible to bind to styled-components or emotion. Even (a (opens in a new tab) f (opens in a new tab)e (opens in a new tab)w (opens in a new tab) p (opens in a new tab)e (opens in a new tab)o (opens in a new tab)p (opens in a new tab)l (opens in a new tab)e (opens in a new tab) were asking for it.
During that time, there were a few efforts to bring type-safety to CSS with bs-css (opens in a new tab) and bs-emotion (opens in a new tab). Even though I liked that approach, it had a few drawbacks:
- The need for learning a new DSL on top of CSS was tedious. Very fancy for simple properties, but almost impossible for more complex ones (a classic example
width: calc(100% - 20px)
becameCSS.width(calc(min, percent(100.), px(20)))
CSS.width(calc(min, percent(100.), px(20)));
). In real world usage I would end up usingCSS.unsafe
. - The runtime was huge. The bundle-size of bs-css starts with 64kb and goes up considerably with the usage, even with ReScripts dead code elimination.
- The fact of having a runtime involved to only write safe CSS doesn't seem like a nice trade-off.
It's possible and a good solution
Embedding CSS inside Reason/OCaml seemed like a bad idea at first, mostly since most CSS-in-JS solutions that use native CSS relied on a JavaScript feature that isn't available in Reason: template literals (opens in a new tab).
After discovering what a ppx was ("a mechanism to embed other languages inside Reason"), and it could mimic the template literals, I jumped straight into hacking a prototype that became this project.
Embedding languages inside others isn't a new concept and has been happening for a long time. In fact, the most common case of an embedded language is usually CSS inside HTML. Using CSS enables all sorts of integrations: Editors, DevTools, prototyping tools, Github Copilot, etc. Even for designers that don't want to understand or care about ReScript.
It can be more powerful than the JavaScript equivalents
Enabling type-safety in CSS is a nice to have, rather than a hard requirement, but nevertheless useful. styled-ppx brings an entire CSS compiler and type-chcker. This enables features from SASS (like supporting future CSS version features) with features from emotion to inline your styles and code together. Features that aren't implemented but are on the horizon are mostly related in extracting the CSS from the runtime and making your styles static at runtime and have zero run-time.
To know more about how it works or what are the benefits I recommend you watch my talk at ReasonSTHLM Meetup (opens in a new tab).
Credits
Here's a list of people that helped me and I couldn't have made styled-ppx without them:
- Javier Chávarri (opens in a new tab): for the introduction to Reason. Teaching me all his knowledge about OCaml, AST, ppx rewriters and the help of bootstrapping the project.
- Alessandro Strada (opens in a new tab): this project started with inspiration from bs-css-ppx (opens in a new tab).
- Eduardo Rafael (opens in a new tab): to teach me how to write a compiler and a type-checker. His initial implementation of the CSS Value definition and the parser combinator.
- Rizo (opens in a new tab): for the help with the API design, discussions and great conversations about styling and CSS.
- Max Lantas (opens in a new tab): for implementing the VSCode extension.
- Egor Chemohonenko (opens in a new tab): for implementing the vim plugin.
- This project builds on a long line of earlier work by clever folks in the JavaScript community from around the world. People from styled-components (opens in a new tab), emotion (opens in a new tab), compiledcssinjs (opens in a new tab), linaria (opens in a new tab), and many more.