Using Tailwind + CSS Modules + SASS and Stylelint with Next.js

April 6, 2021 Update

This article was originally based on Tailwind CSS v1.x. Today I've had some time to upgrade to v2.1 and it didn't require any configuration changes beyond what is noted in Tailwind CSS Upgrade Guide. If you are starting from scratch the most important changes are that post-css and autoprefixer are now required dependencies.

When I first built this site I chose SCSS along with CSS Modules to style it because I was familiar with this approach. That was pretty easy to do with the help of the respective sections in Next.js documentation.

After having a working version of the site I revisited the idea to finally play a little with Tailwind CSS and see if it could fit within my workflow and styles architecture. I set the following requirements that I wanted the integration to satisfy:

  • It should allow defining base styles for the whole site.
  • It should be possible to keep styles separated in SCSS partial files.
  • It should allow defining styles using Tailwind in CSS Modules.
  • Allow me to take advantage of Tailwind CSS and its flexibility.
  • Allow nesting styles with SCSS

After a couple of hours trying different approaches and configurations, I finally was able to come up with a working solution that satisfies my needs.

Let's jump into the solution and implementation!

1. Configuration

1.1. Pre-requisites

I previously had SCSS and CSS Modules working on my site. Follow the instructions in the docs and you should be ready.

1.2. Add Tailwind CSS to the Project

For this I simply followed the Tailwind CSS example in the Next.js repository.

1.3. Configure Tailwind

Nothing special to do here. I just modified tailwind.config.js to adjust the paths to my components and pages folders for the purge directive as I have my source code under the ./src. I also extended the colors and fonts configurations.

module.exports = { purge: [ './src/components/**/*.{js,ts,jsx,tsx}', './src/pages/**/*.{js,ts,jsx,tsx}' ], theme: { extend: { colors: { black: '#000000', cornflower: { default: '#8ec6eb', medium: '#b1d7f1', light: '#e5f2fa' }, 'steel-blue': { default: '#4b89b3', dark: '#162a39' }, white: { default: '#ffffff', 'transparent-10': 'rgba(255 255 255 / 10%)' } }, fontFamily: { primary: ['"Noto Serif"', 'serif'], secondary: ['"Quattrocento Sans"', 'sans-serif'] } } }, variants: {}, plugins: [] };

2. Using Tailwind in Base Styles

2.1. Creating the Main SCSS file for Styles.

I added an src/styles/main.scss file containing the imports of SCSS partials files. As you can see in the following example it's not really different than what you do in the normal implementation:

@tailwind base; /* Write your own custom base styles here */ @import './_base.scss'; @import './_typography.scss'; /* Start purging... */ @tailwind components; /* Stop purging. */ /* Write you own custom component styles here */ /* Start purging... */ @tailwind utilities; /* Stop purging. */ /* Your own custom utilities */

The only difference here is that we use imports instead of declaring styles right in the file. This is something I didn't like about Tailwind but this seemed a good workaround for me.

2.2. Declaring Base Styles Using Tailwind

Let's take a look at how to work with Tailwind in our SCSS files.

// file: ./src/styles/_typography.scss // Importing external CSS code, fonts, etc. @import url(',wght@0,400;0,700;1,400&display=swap'); @import url(',wght@0,400;0,700;1,400&display=swap'); // Using Tailwind with `@apply` in rules h1, h2, h3 { @apply my-4 font-secondary text-cornflower font-normal; } h1 { @apply text-3xl; // You can use normal CSS properties too for properties Tailwind doesn't handle: background-color: rgba(0, 0, 0, 0.35); @screen lg { // Important: note that you can't use `lg:text-4xl` as you would // normally do when working with classes in HTML. For this you // must use the `@screen` directive and the respective breakpoint. @apply text-4xl; } } a { @apply text-cornflower underline; &:hover { // Important: similar to what we did for media queries, we must // declare styles for pseudo-selectors using its own rule. // Using `hover:text-white` will throw an error when styles compile. @apply text-white; } }

2.3. Import Styles in ./pages/_app.js

I simply added the SCSS file import:

import Head from 'next/head'; import '../styles/main.scss'; // This default export is required in a new `pages/_app.js` file. export default function MyApp({ Component, pageProps }) { return <Component {...pageProps} />; }

That's it! You should have your base styles implementation working wonderfully at this point! Important: this requires restarting the Next.js server.

3. Using Tailwind in CSS Modules

To add styles using Tailwind in our CSS Modules for components is pretty much the same as we did for our base styles.

3.1. Import the styles module file into our component

// file: `./src/components/Header/Header.jsx` import styles from './Header.module.scss'; const Header = () => { return <header className={styles.wrapper}>{/* component code... */}</header>; }; export default Header;

3.2. Add Module Styles

I used @apply, nesting, and Media Queries the same way I did for base styles:

.wrapper { @apply py-4 border-b border-solid border-white-transparent-10; @screen lg { @apply border-0 pt-10 pb-8; } }

Done! Now your component is styled with Tailwind CSS! 🙌

4. Bonus: Configure Stylelint to Format and Order Properties automatically

Note: this is intended for VSCode users but can be easily done in npm scripts or translated to other code editors.

4.1. Install Dependencies

yarn add --dev stylelint stylelint-config-recommended-scss stylelint-order stylelint-scss

4.2. Add Stylelint Configuration

/* file: ./.stylelintrc.json (remove this comment, no valid JSON) */ { "extends": "stylelint-config-recommended-scss", "plugins": ["stylelint-order", "stylelint-scss"], "rules": { "order/properties-alphabetical-order": true, "scss/at-rule-no-unknown": null, "scss/at-import-no-partial-leading-underscore": null } }

4.3. Install VSCode Extension and Configure it For Your Project Folder

// file: ./.vscode/settings.json { "editor.formatOnSave": true, // Run Stylelint fix when you save the file "editor.codeActionsOnSave": { "source.fixAll.stylelint": true }, // Recommended config for the extension "css.validate": false, "less.validate": false, "scss.validate": false }

You're ready. Now when you save your .scss file you should see Stylelint applying the fixes and sorting properties:


Well. It's not very hard to get it to work once you've put all the pieces together and connected them correctly. Don't you think?

I hope these notes can be helpful to anyone who may be having a hard time implementing something similar. I would love to see your comments, corrections, or questions as well as alternative approaches you could have.

Publicado el 17 de agosto de 2020. Esta nota es sobre: styles, css, tailwind-css, css-modules, stylelint, next-js.