When it comes to styling, React Native is in a pretty good spot. The built-in StyleSheet approach allows you to easily decouple the styles outside of JSX.
Sticking with React Native is usually a good idea, however it’s not without its own flaws. For one, it can be difficult to maintain styles in some external locations to reuse them. Another issue is managing proper naming conventions throughout the whole codebase. These issues can be resolved by using Tailwind in React Native.
Tailwind CSS completely changes the common approach to structuring CSS. While learning good code practices, developers quickly understand the importance of separation of concerns and splitting HTML and CSS between two files. Utility-first CSS seems completely different.
While there is some dissatisfaction with utility-first CSS coming from the developer community, it’s hard not to notice that Tailwind CSS is spiking in popularity. As a testament to its capabilities, Tailwind won an award for being the most adopted technology in The State of CSS 2020 survey.
So, what’s all the fuss about?
In React Native, utility-first classes apply specific CSS properties to an element via its class or style property. The previous approach was to apply the style object to the element inline or reference the keys of the StyleSheet object with custom names applied.
The utility-first class approach allows you to simply add a class name to the element without needing to write custom styles. The decision to implement colors, typography, and structure, as well as provide a meaningful name to every styled element, is already made.
Tailwind gives you default values based on a solid design system, which results in consistency throughout the whole codebase. The learning curve may seem steep at first, but a developer who is proficient with that type of styling is able to work faster and in a more unified way. In addition, when a team uses a curated set of limited options, it’s easier to onboard a new developer and maintain consistency in your styling approach.
Lastly, because StyleSheets are reused, the codebase will stop growing and therefore easier to maintain.
Using styled-components is a great approach to styling for many reasons. However, not knowing at first glance whether a given component is React or a dumb-styled one can really slow things down. There is also a case of premature abstraction when we create components that are never reused.
When it comes to mixing code with Tailwind classes, one downside is that our code can quickly become verbose. Usually, we avoid inline styles at all costs because they negatively impact the readability of the code and may impair overall performance. There has been some suggestion from the developer community that StyleSheet approach is more performant than inline styles because it sends the whole object through the bridge at once. This is further clarified in the React Native Source Code.
While there are a few Tailwind packages well suited for React Native, I chose to use tailwind-react-native-classnames
over tailwind-rn
. tailwind-react-native-classnames
is based on Classnames, a JavaScript utility that is used to improve Tailwind code on the Web, and therefore should be more familiar to developers using Tailwind CSS.
You can feel free to use different libraries as you please, but to me, the tagged template function approach is more visually appealing than styles passed to the array like in react-native-tailwindcss
. You may also choose to simply import React Native components from the react-native-tailwind
library and pass classes to the className
prop.
There are two approaches to apply Tailwind classes to the element using the tailwind-react-native-classnames
library. The basic one uses the ES6 tagged template function, which simply wraps class names in backticks like in the View
element below. The second approach, which uses the Classnames package, allows for combining classes and handling more complex cases. Notice it in the Text
element below:
import tw from 'tailwind-react-native-classnames'; const MyComponent = () => ( <View style={tw`bg-blue-100`}> <Text style={tw.style('text-md', invalid && 'text-red-500')}>Hello</Text> </View> );
We have two React Native classes for using platform-specific styles, which can be safely used with the tagged template function:
tw`ios:pt-4 android:pt-2`;
If you look at the menu on the left side of the Tailwind homepage, you’ll see several sections. Only some of these are relevant to React Native, but if you already know how to style components in React Native, you’ll quickly grasp what you can use. The most interesting sections for you to read are:
There is also the Effects section where you can find opacity, but it is also possible to use classes. Use shadow
in tailwind-react-native-classnames
, which is located in the Box Shadow part of this section.
I also found this cheat sheet very useful. When trying to specify values, you can check for the proper code for element attributes. For example, when you set element width, you can use the w-
class name and set the number w-40
to get 160px.
Now, let’s build a simple layout using both approaches to compare Tailwind code to React Native code. For this example, I decided to create ScrollView with cards. A selected variable is passed to the component, which determines different backgrounds and colors of the title set.
The whole code example for this article is located in the Git repository TailwindCssReactNative. You can also run the example from Expo. To start, we’ll build the component above using the StyleSheet approach:
const ListItem = ({ uri, selected = false, text="" }) => { return ( <View style={[styles2.container, { ...(!selected && { backgroundColor: '#FFFFFF'})}]}> <View style={styles2.logoBackground}> <Image style={styles2.logo} source={ uri } /> </View> <Text style={[styles2.text, { ...(!selected && { color: 'black'})}]}>{ text }</Text> <TouchableOpacity style={styles2.button}> <Text style={styles2.buttonText}>Details</Text> </TouchableOpacity> </View> ) }
As you can see, there are three props passed: uri
for the image, text
for the card title, and information about whether the component is selected or not. Based on whether selected
is true or false, there are additional styles added like backgroundColor
in the main view and color
in Text
component.
StyleSheet is used to style this component:
const styles2 = StyleSheet.create({ container: { height: 256, width: 160, backgroundColor: 'rgba(59,130,246,1)', borderRadius: 12, padding: 15, margin: 5, alignItems: 'center', justifyContent: 'center', shadowColor: "#000", shadowOffset: { width: 0, height: 3, }, shadowOpacity: 0.27, shadowRadius: 4.65, elevation: 6, }, logoBackground:{ width: 112, height: 112, borderRadius: 55, backgroundColor: '#E4F0FE' }, logo: { width: 110, height: 110, borderRadius: 55 }, text: { color: 'white', fontSize: 18, fontWeight: 'bold', marginVertical: 10 }, button: { height: 40, width:'100%', backgroundColor: 'white', borderRadius: 20, alignItems: 'center', justifyContent: 'center', borderWidth: 1, borderColor: 'rgba(59,130,246,1)' }, buttonText: { color: 'rgba(59,130,246,1)', fontSize: 17, fontWeight: 'bold' } });
Now, we can build the same component with the Tailwind CSS approach and the tailwind-react-native-classnames
library.
import React from 'react'; import { Text, View, TouchableOpacity, Image } from 'react-native'; import tw from 'tailwind-react-native-classnames'; export const ListItemTW = ({ uri, selected = false, text="" }) => ( <View style={tw.style( 'h-64 w-40 bg-blue-500 rounded-xl p-4 m-1 items-center justify-center shadow-lg', !selected && 'bg-white' )}> <View style={tw`w-28 h-28 rounded-full bg-indigo-50`}> <Image style={tw`w-28 h-28 rounded-full`} source={ uri } /> </View> <Text style={tw.style( 'text-white text-lg font-bold my-4', !selected && 'text-black' )}> { text } </Text> <TouchableOpacity style={ tw`h-10 w-full bg-white rounded-full items-center justify-center border border-blue-500` } > <Text style={tw`text-lg text-blue-500 font-bold`}> Details </Text> </TouchableOpacity> </View> )
So, what’s the difference? Notice that the Tailwind component has 36 lines compared to the normal component with StyleSheet that has 76 lines. The biggest drawback is that there are several long lines of code. Two of these are even multi-line on account of using Classname’s tw.style
to join classes with conditionally added styles.
Using predefined styles has its pros and cons. As mentioned, benefits include faster development time and ease of maintenance. The biggest downside is that if you use some uncommon value, like a size or color that is not included in standard values, you would have to customize your styles. I think that the simplest approach would be to pass the style object to the tw.style
, which should be recognized without any problem.
Using Tailwind CSS in your project provides unification of the whole codebase. Instead of giving custom names to the styles in StyleSheet, you can apply class names from the predefined list that is well known by many developers.
Additionally, the speed of development should be improved because it’s easier to style components and to assess what styles are applied to particular elements. This approach also has its downsides, like making some components too verbose. I believe that these problems can be resolved by either exporting some of the longer, reusable parts as styled-components or exporting them to the external file, but it’s up to you to decide the best approach for your project.
LogRocket is a React Native monitoring solution that helps you reproduce issues instantly, prioritize bugs, and understand performance in your React Native apps.
LogRocket also helps you increase conversion rates and product usage by showing you exactly how users are interacting with your app. LogRocket's product analytics features surface the reasons why users don't complete a particular flow or don't adopt a new feature.
Start proactively monitoring your React Native apps — try LogRocket for free.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowCreate a multi-lingual web application using Nuxt 3 and the Nuxt i18n and Nuxt i18n Micro modules.
Use CSS to style and manage disclosure widgets, which are the HTML `details` and `summary` elements.
React Native’s New Architecture offers significant performance advantages. In this article, you’ll explore synchronous and asynchronous rendering in React Native through practical use cases.
Build scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
5 Replies to "Why you should use Tailwind CSS with React Native"
Well two years back, I did real projects with similar concept. I see It is highly productive. Here is my repo:
https://github.com/WaftTech/helperStyles
Can I add custom color to it?
Is there any data comparing performance of this approach vs using StyleSheets? The code looks nice and like something I would like to try but without any performance comparison it is hard to decide if it’s a good idea to use it on a big project.
Try https://github.com/mathieutu/babel-plugin-tailwind-rn-classname. It allows use tailwind-rn like in web project, by className string. It’s also Tailwind CSS InteliSense compatible.
how can one add custom font?