gust
is great for custom components, but right now, the React Native ecosystem almost always needs to pass style objects around.React Native is very behind the web when it comes to UI libraries. There’s two likely reasons for this: CSS on the web is easy and the object known as StyleSheet
in React Native is not.
At a fundamental level, the syntax of StyleSheet
causes a lot of problems. It looks like CSS (the kind you’d use in React’s style
prop), it acts like CSS (most of the time) just like you’d expect in a browser, but then you encounter one of dozens of scenarios where React Native takes the CSS specification and yeets it out the nearest window.
- Shadows are a custom object syntax instead of a conversion of
box-shadow
- Random elements such as
ScrollView
introduce custom non-standard props such aselevation
, but also only for specific platforms - You get flexbox. Only flexbox. Everything flexes. Everything is boxes. Except for the
flex
property which has decided it is not actuallyflex
as you’d expect but just a number that translates to a percentage. But not a useful number-to-percentage like55
meaning55%
. Instead, you get an alternate universe number that is expressed as a ratio based on the sum of all flex properties on sibling nodes. It’s a universe whereflex:1
means both100%
and50%
based on elements outside of its rendering tree. /rant
Yes, a lot of this will be fixed over time as React Native continues to improve on its style interpreter, but we are still converting from CSS to platform-specific layout calls. I don’t think we’ll ever reach parity, but I’d also like to avoid the programming equivalent of “hammering my thumb” every time I lay things out in a mobile app.
The truth is, what I want is something as easy as Tailwind CSS in React Native. If you haven’t tried Tailwind yet, you should. It’s trivial to make something look good, and it’s adaptable enough withstand design changes. In React Native, there's a few really solid options:
- tailwind-rn(github, npm) is the OG of Tailwind in your React Native projects. It works by converting the Tailwind styles into JSON, which is memoized in your app on access. Because it tries to be only a translation layer between systems, complex behaviors such as breakpoints and React Native's Appearance are not supported out of the box.
- tailwind-rn-gust (archived github, npm) extends the
tailwind-rn
library by adding utilities for custom component creation. By introducing a React Component generator, it's possible to add additional props to turn "on" flags inside of a call totailwind-rn
's style generator. _However, I wouldn't recommend this, as the components add an additional layer of complexity once you want to useAnimated.View
or other 3rd party components that want to leverage thestyle
prop for stylistic behavior. - twrnc (github, npm) Is what I'm currently using and it leverages Tailwind's JIT Compiler to remove the built steps inherent in other Tailwind-bridging systems. Out of the box, it uses React Native's hooks for figuring out screen sizes and appearance, making it easier to use normal Tailwind prefixes such as
lg:text-xl
.
Originally, this post focused on tailwind-rn-gust
, but I think it's becoming more clear that until there's an official Tailwind for React Native, twrnc
is going to be the truest-to-Tailwind experience you'll find on the platform.
Instead, here's how you'd accomplish something like a rich "press" interaction using twrnc
. (You can also put both styles into a single tw.style
call, but I find it easier to read leveraging the array syntax supported for multiple style objects.)
<MyComponent style={({pressed}) => [
tw`bg-red-500`,
tw.style({
"bg-blue-500": pressed
})
]} />
The best thing about the tw
helper is that it's built for generating style
objects, meaning it'll work with Moti, Reanimated 2, and many other component libraries that focus on the style
prop.
Gust Archived
And so, with great alternatives out there, gust
is archived. The entire library is only 159 lines and is easy to port into your own existing React Native project if you need the features. However, until we see something like a native className
in React Native, the style
tag is going to be the default operating mode for rich styles, animation, and state based effects.