TL;DR: Modern styling in React includes CSS Modules, Styled Components, and Tailwind CSS.
Styling is an essential and integral part of modern web development. It has been the tagging partner of HTML since the inception of the browser, providing all the shine to HTML elements and webpages. It attracts users and encourage them to use a website for longer through a better user experience.
The way we write style has been evolving with modern JavaScript frameworks. In modern libraries like React, component-driven development provides abstraction at the unit level on the UI or webpage, where the business logic and state are isolated to the component itself. Styles have also evolved to be abstracted to the components themselves. These components can be extended or composed to create modules or other UI components of the webpage.
Long gone are the days when we struggled with global class names that could conflict with different HTML elements on other webpages, especially in the large codebase.
Modern JavaScript frameworks like React allow you to write styles at the component level. You can have the same class names for different components, but they won’t conflict. Kudos to modern bundling tools such as Webpack, which generate unique classes and styles to avoid conflict.
They also support code-splitting and tree-shaking styles, which allow us to load the styles specific to the components rather than everything at once, optimizing the page speed.
In this article, we are going to see multiple ways of styling specific to React:
CSS Modules are defined by naming the CSS files *.modules.css, which allows you to access the CSS classes and animations defined in the stylesheet as JavaScript objects. You can assign them to the React elements.
app.module.css
.yellow { color: yellow; }
import Styles from "./app.module.css"; const App = () => { return ( <> <h1 className={Styles.yellow}>Hello World!</h1> </> ); }; export default App;
The classes and animations are scoped locally to the component, and React provides support for the CSS Modules under the hood, so you don’t have to make any configuration changes. You can import the CSS Modules file in your component and then use the import alias to access the CSS classes as objects.
The only problem with this is that you cannot merge to a class like you do while defining the normal CSS class in the string.
<h1 className="yellow large">Hello World!</h1>
This is because the CSS is now converted to ICSS, a low-level compilation of CSS that can be accessed as JavaScript objects.
To use multiple CSS classes together, we will need to use packages, such as classnames, that allow us to merge CSS styles accessed as objects.
app.module.css
.yellow { color: red; } .large { font-size: 3em; }
import Styles from "./app.module.css"; import cx from "classnames"; const App = () => { return ( <> <h1 className={cx(Styles.yellow, Styles.large)}> Hello World!</h1> </> ); }; export default App;
CSS Modules promote modularity, but we still have to maintain a separate style file to define the styles. Some developers find this better, as it provides a separation of concerns, as the business logic and styles are separate, while many prefer to have everything in a single file.
Styled Components allow us to write CSS in JavaScript, completely eliminating the need to maintain separate styling files. This keeps all three layers of a webpage in a single file: HTML, CSS, and JavaScript.
With Styled Components, we keep the styles isolated from the components in the true sense. It is a powerful way of styling the component that allows us to use React’s capabilities in the complete sense that the Styled Components can be used as a React component.
Let’s see some practical examples of the Styled Components to understand them better.
# npm npm install styled-components # yarn yarn add styled-components
ES6 has introduced tagged template literals, in which you can tag a string literal to the function accessed inside it. Styled Components use them to define their styles.
import Styled from "styled-components"; const Button = Styled.button` background: transparent; border-radius: 3px; color: black; border: 1px solid; display: inline-block; margin: 0.5em 1rem; padding: 0.5em 0; transition: color .25s ease; cursor: pointer; `;
With Styled Components, you can define the React component itself rather than applying the CSS style to the HTML element explicitly.
The variable Button can be used as the React component, whereas the object accessed from the Styled.button defines the HTML element that will be created, which in this case is the button.
const Test = () => { return ( <> <Button>Click me</Button> </> ); }; export default Test;
The style is directly applied to the HTML element, and we can apply all sorts of styles as we do in the CSS, even on pseudo-states.
const Button = Styled.button` ... &:hover{ color: red; } `;
As styled components create React elements, we can pass props to them and access them. They can be used to apply dynamic styles.
import Styled from "styled-components"; const Button = Styled.button` background: ${(props) => (props.filled ? "gray" : "transparent")}; border-radius: 3px; color: ${(props) => (props.filled ? "white" : "black")}; border: 1px solid; display: inline-block; margin: 0.5em 1em; padding: 0.5em 0; transition: color .25s ease; cursor: pointer; &:hover{ color: ${(props) => (props.filled ? "blue" : "red")}; } `; const Test = () => { return ( <> <Button filled>Click me</Button> </> ); }; export default Test;
This promotes the container/presentational pattern of the development in React, where the component does not maintain its state, but changes based on the props it receives.
This helps to create a design system with the Styled Components, where the designers can create basic sets of common components that React developers can use to create other components.
This is also possible because it is easier to extend the style of the HTML elements or elements created using Styled Components.
import Styled from "styled-components"; const Button = Styled.button` background: ${(props) => (props.filled ? "gray" : "transparent")}; border-radius: 3px; color: ${(props) => (props.filled ? "white" : "black")}; border: 1px solid; display: inline-block; margin: 0.5em 1em; padding: 0.5em 0; transition: color .25s ease; width: 10em; cursor: pointer; &:hover{ color: ${(props) => (props.filled ? "blue" : "red")}; } `; const GreenButton = Styled(OutlinedButton)` background: green; border-color: yellow; `; const Test = () => { return ( <> <Button filled>Click me</Button> <GreenButton filled>I am Green</GreenButton> </> ); }; export default Test;
When we extend the styles, it overwrites the existing ones and applies the new ones.
The props are passed down in the hierarchy automatically and can be accessed in both the extended component and the base component. We can also compose the Styled Components as normal React components.
import Styled from "styled-components"; const Wrapper = Styled.main` padding: 10px; max-width: 1100px; margin: 0 auto; `; const HeroArea = Styled.section` background: green; height: 65vh; `; const Test = () => { return ( <Wrapper> <HeroArea>Hello World!</HeroArea> </Wrapper> ); }; export default Test;
Many popular CSS frameworks emerged before Tailwind, including Bootstrap and Foundation. These frameworks provided a pre-defined set of components and styles that we had to use as they stated.
Tailwind CSS has tried to shift away from traditional methods of writing styles by providing a set of low-level utility classes that you can use to create your custom designs, similar to Lego blocks. This makes it a utility-first CSS framework.
To start using Tailwind CSS in your React project, you need to initialize it. This involves installing Tailwind CSS and its dependencies and setting up the necessary configuration files.
Install Tailwind CSS and dependencies:
In your project directory, run the following command to install Tailwind CSS along with PostCSS and Autoprefixer.
npm install tailwindcss postcss autoprefixer
Initialize Tailwind CSS:
Use the following command to generate the Tailwind CSS configuration file (tailwind.config.js) and the PostCSS configuration file (postcss.config.js).
npx tailwindcss init -p
Adding the -p flag ensures that the files tailwind.config.js and postcss.config.js are created.
The tailwind.config.js file allows you to customize your Tailwind CSS setup. You can extend the default configuration, add custom themes, and configure other settings.
To optimize your CSS file size for production, configure the purge option. This option removes any unused CSS classes from your final build. Open tailwind.config.js and update the content property.
module.exports = { purge: ["./src/**/*.{js,jsx,ts,tsx}", "./public/index.html"], darkMode: false, // or 'media' or 'class' theme: { extend: {}, }, variants: { extend: {}, }, plugins: [], };
This configuration ensures that Tailwind CSS scans all JavaScript, TypeScript, and HTML files for class names in the src and public directories.
You can extend the default theme by adding custom colors, fonts, spacing, and more. For example, to add a custom color, modify the theme property.
module.exports = { purge: ["./src/**/*.{js,jsx,ts,tsx}", "./public/index.html"], darkMode: false, // or 'media' or 'class' theme: { extend: { colors: { primary: "#1DA1F2", secondary: "#14171A", }, }, }, variants: { extend: {}, }, plugins: [], };
The above example adds two custom colors: primary and secondary.
Tailwind CSS can be extended with plugins to add additional functionality. For instance, you can add forms or typography plugins. Install the plugin and add it to the plugin array.
const forms = require("@tailwindcss/forms"); module.exports = { purge: ["./src/**/*.{js,jsx,ts,tsx}", "./public/index.html"], darkMode: false, // or 'media' or 'class' theme: { extend: {}, }, variants: { extend: {}, }, plugins: [forms], };
In this example, the @tailwindcss/forms plugin is added to enhance the styling of form elements.
Now that you have Tailwind CSS installed and configured, the next step is to integrate it with your Create React App project.
Create a CSS file if it doesn’t already exist (e.g., src/index.css ) and add the following Tailwind CSS directives.
@tailwind base; @tailwind components; @tailwind utilities;
These directives import Tailwind’s base styles, components, and utility classes into your CSS.
Open src/index.js (or src/index.tsx if you’re using TypeScript) and import the CSS file at the top.
import './index.css';
Start your development server to ensure everything is configured correctly.
npm start
You can now start using Tailwind CSS classes in your React components. For example, open src/App.js and modify it to include some Tailwind CSS classes.
function App() { return ( <div className="App"> <header className="bg-blue-500 text-white p-4"> <h1 className="text-3xl">Welcome to My Tailwind CSS React App</h1> </header> <main className="p-4"> <p className="text-gray-700"> This is a simple example of using Tailwind CSS with React.{" "} </p> </main> </div> ); } export default App;
Open your browser and navigate to http://localhost:3000 to see your React app styled with Tailwind CSS. You should see a header with a blue background and white text, and a paragraph with gray text.
The utility-first approach in Tailwind CSS is a fundamental shift from traditional CSS methodologies. Tailwind has a set of low-level utility classes that we can directly assign to the HTML elements to create different designs.
Key benefits
Example
Instead of writing the following custom CSS:
<div class="my-component"> <h1 class="title">Hello World</h1> <p class="description">Welcome to my website.</p> </div> <style> .my-component { padding: 16px; background-color: #f8f8f8; } .title { font-size: 24px; color: #333; } .description { font-size: 16px; color: #666; } </style>
You use Tailwind utility classes, like in the following code.
<div class="p-4 bg-gray-100"> <h1 class="text-2xl text-gray-900">Hello World</h1> <p class="text-lg text-gray-600">Welcome to my website.</p> </div>
Tailwind CSS provides a comprehensive set of utility classes and directives to style your HTML elements. These classes are categorized into several groups:
container //Centers the content with responsive padding. box-border, .box-content //Sets the box-sizing property. block, inline-block, inline //Controls element display type.
Example
<div class="container mx-auto"> <div class="block bg-white p-4">Content</div> </div>
flex, inline-flex //Enables flexbox on an element. flex-row, flex-col //Sets the flex direction. grid, inline-grid //Enables grid layout on an element.
Example
<div class="flex flex-col items-center"> <div class="flex-1 bg-blue-500">Item 1</div> <div class="flex-1 bg-green-500">Item 2</div> </div>
m-4, p-4 //Sets margin and padding. mx-auto //Horizontally centers an element with auto margins. space-x-4, space-y-4 //Adds space between child elements.
Example
<div class="p-4"> <div class="m-4 bg-red-500">Content</div> </div>
w-1/2, h-1/4 //Sets width and height as fractions. w-full, h-screen //Sets width and height to full size.
Example
<div class="w-1/2 h-1/4 bg-yellow-500">Content</div>
text-lg, text-2xl //Sets font size. font-bold, italic //Sets font weight and style. text-center, text-left //Sets text alignment.
Example
<p class="text-lg font-bold text-center">Hello World</p>
bg-blue-500, bg-red-200 //Sets background color. border, border-2 //Sets border width. rounded, rounded-lg //Sets border radius.
Example
<div class="bg-blue-500 border border-2 border-red-500 rounded-lg">Content</div >
Tailwind CSS includes built-in responsive design utilities that allow you to apply styles at specific breakpoints. The default breakpoints are:
sm (640px) md (768px) lg (1024px) xl (1280px) 2xl (1536px)
Example
To apply a utility class at a specific breakpoint, prefix it with the breakpoint name followed by a colon.
<div class="bg-red-500 sm:bg-green-500 md:bg-blue-500 lg:bg-yellow-500 xl:bg-pu rple-500"> Responsive Content </div>
In this example, the background color changes at different screen widths.
<div class="flex flex-col md:flex-row"> <div class="flex-1 bg-red-500">Item 1</div> <div class="flex-1 bg-green-500">Item 2</div> </div>
This layout stacks the items vertically on small screens and arranges them in a row on medium and larger screens.
Tailwind CSS is highly customizable. You can modify the default configuration to fit your design requirements. Customizations are included in the tailwind.config.js file.
You can add custom colors, spacing, fonts, and more.
module.exports = { theme: { extend: { colors: { primary: "#1DA1F2", secondary: "#14171A", }, spacing: { "128": "32rem", }, fontFamily: { sans: ["Graphik", "sans-serif"], }, }, }, variants: {}, plugins: [], };
You can define your breakpoints if the defaults don’t fit your needs.
module.exports = { theme: { screens: { xs: "480px", sm: "640px", md: "768px", lg: "1024px", xl: "1280px", "2xl": "1536px", }, }, };
Plugins are used to add additional functionalities to Tailwind CSS. For instance, you can add a forms plugin to style form elements.
const forms = require('@tailwindcss/forms'); module.exports = { theme: { extend: {}, }, plugins: [forms], };
The @apply directive allows you to compose utility classes in your CSS files.
.btn { @apply bg-blue-500 text-white font-bold py-2 px-4 rounded; }
In this example, you create a .btn class that applies several utility classes simultaneously.
A navigation bar is a crucial component of many web apps, allowing users to navigate through different sections of the site. With Tailwind CSS, you can create a stylish and responsive navigation bar easily.
<nav class="bg-white shadow-md"> <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div class="flex justify-between h-16"> <div class="flex"> <a href="#" class="flex-shrink-0 flex items-center"> <img class="h-8 w-8" src="logo.svg" alt="Logo"> </a> <div class="hidden sm:ml-6 sm:flex sm:space-x-8"> <a href="#" class="text-gray-900 inline-flex items-center px-1 pt-1 b order-b-2 border-indigo-500 text-sm font-medium">Home</a> <a href="#" class="text-gray-500 hover:text-gray-700 inline-flex item s-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium">About</a> <a href="#" class="text-gray-500 hover:text-gray-700 inline-flex item s-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium">Services </a> <a href="#" class="text-gray-500 hover:text-gray-700 inline-flex item s-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium">Contact</ a> </div> </div> </div> </div> </nav>
Explanation
Combining Tailwind CSS with React can significantly enhance your web app development experience and performance. Following are some of the key benefits.
Thanks for reading this article! The evolution of styling in web development with tools like CSS Modules, Styled Components, and Tailwind CSS has greatly enriched the developer’s toolkit. Each of these methods brings its own strengths to the table. By understanding and applying these techniques effectively, developers can ensure that their web apps are not only visually appealing but also maintainable and scalable.
The choices in styling methods can profoundly impact the development workflow and the final user experience. It’s worth investing the time to explore these options and integrate them into your web development practices to achieve optimized, conflict-free, and engaging web apps.
The Syncfusion React UI components library is the only suite you will ever need to build an app. It contains over 85 high-performance, lightweight, modular, and responsive UI components in a single package.
The newest version of Essential Studio® is available on the license and downloads page for existing Syncfusion customers. If you are not yet a customer, try our 30-day free trial to test the latest features.
You can always contact us through our support forums, support portal, or feedback portal. We are always happy to assist you!