Customize TailwindCSS to give your sites a unique look

Learn how to customize the default styles of a TailwindCSS application
Feature Image

Front-end development is fascinating, not only because you can create magical experiences and it is very tangible to see the results of your work, but also because of the vast number of options available for building UIs.

Regularly we face the decision to pick from fantastic JavaScript frameworks and CSS or visual design frameworks, which grew up so complex that they have their own learning curve.

After the immense success of frameworks like bootstrap , the trend was set, and the race for frameworks was intense, and CSS was abstracted each time a bit more into components, rules, and whatever these frameworks created. But how did customizations happen? With good old CSS, or SCSS in some cases.

But TailwindCSS is not a framework like any other.


What is Tailwind CSS?

TailwindCSS broke the paradigm followed by other frameworks, going back to the roots and rethinking how we style UIs.

When React came out and presented the idea of moving the “HTML” and the JavaScript back to one file, everyone freaked out, but it turned out to be something great. Similarly, TailwindCSS proposes moving the styles from CSS to the “HTML” or JavaScript files by providing a set of utility classes that do not represent custom components but CSS properties, and they have classes for all.

Wait, what? Isn’t my CSS going to be huge? No. Thanks to tailwind processors, your final CSS (as yes, in the end, you will have a CSS file generated by Tailwind) will only be composed of those classes you used on your project.

Let’s see an example of how we used to do it, and how it works with TailwindCSS:

<!-- with CSS -->
<style>
.title {
  font-weight: bold;
  color: #333;
  /* ... */
}
</style>

<h4 class=”title”>Good old fashioned title</h4>

<!-- with TailwindCSS -->
<h4 class="font-serif text-4xl leading-normal font-bold text-gray-700">Want to dig deeper into Tailwind?</h4>

If you are like me, you will be skeptical, but believe me, it works. It’s so much better and faster to understand how components will look by simply looking at the code. Additionally, if you work on medium or large projects, CSS classes go out of control, having things like “title”, or “title2”, and you never know which one to use.

Another benefit is something called “Preflight”, which is a set of styles. TailwindCSS injects that establish the same baseline across all browsers, so no more things look different in Safari than in Firefox or Chrome.

But there’s more. Because TailwindCSS is fully customizable, you can preset your style guidelines into your configuration and build interfaces following your guidelines with ease, and that’s what we will be focusing more on today.


What will we be making?

As discussed before, we will learn how to customize TailwindCSS to give a unique look at your websites and apps. For that, we will build a React application demonstrating how Tailwind can be customized, though the same concepts will apply to any other framework or non-framework website.

If you have some experience with Tailwind, you will recognize its unique design from the examples, using one of the preset colors and fonts. And if you try to build a newsletter sign up form, it will probably look something like this:

Original TailwindCSS design

Original TailwindCSS design

But our designers don’t want to use any of the given colors, and they want to customize the shape of buttons, inputs and fonts, our final produced design looks as follows:

Not sure if much nicer, but designers probably know better.

New improved design

New improved design


Setting up your application

Setting up TailwindCSS may seem a bit extra complicated for a CSS framework, but remember, it is much more than that. To make sense, Tailwind needs to understand your project, which classes you are using to optimize the build size. Those classes could be in JSON files, React components, stuff from VueJS, so it has to be pretty smart and have some special access.

I won’t bore you with the details on how to set it up. It’s not super complicated, but it does require you to follow some steps, and it’s all very well documented on their site. They also provide the instructions for multiple frameworks.

If you don’t know how, please review the official installation guide , get a project up and running, and come back to continue here.


Building the form with default styles

We won’t spend much time here, we are building a simple form with just one input and one button, but the final code for our base design is as follows:

return (
   <div className='App' style={{ marginTop: '50%' }}>
     <form className='text-lg'>
       <input
         className='p-4 mr-2 border font-medium rounded-md border-purple-600 outline-none'
         placeholder='Enter your mail'
       />
       <button
         className='py-4 px-6 rounded-md text-white font-medium rounded-lg bg-purple-600 hover:bg-purple-700 outline-none'
         type='submit'
       >
         Sign up
       </button>
     </form>
   </div>
 );

After that you should see something like this on your website:

Demo of original design

Demo of original design


Customizing the styles

Although the above form looks pretty good, what if your designer comes in between their own set of design systems with a new color palette, spacing changes, and font family updates?

Here is where Tailwind shines bright. You can change almost every aspect of the default styles provided to you in a couple of lines, and that too isn’t much complex. It just takes some changes in the configuration files, and boom, there you go! Exciting, right? Let’s start configuring!


Configuring the Tailwind default presets

Head over to tailwind.config.js file. Let’s take a look at each of the objects we get out of the box:

module.exports = {
  purge: [],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  // ...
}
  • purge : this is used to tree-shake unused styles and optimize the final build size of your Tailwind project. It can take in an array of file names or file types which you want to optimise. Most likely, you would want to optimise all those files or components where Tailwind is used in one way or the other. Here’s a common example:
purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html']
  • darkMode : Tailwind includes a dark variant that lets you style your site differently when dark mode is enabled. We can simply pass ‘media’ as its value to start using dark mode utility classes.
module.exports = {
  darkMode: 'media',
  // ...
}
  • theme : here you can define your project’s color palette, type scale, fonts, breakpoints, border radius values, and more. Basically, this is where all the nitty-gritty of customisation actually occurs. It can have child objects too like screens , colors , spacing etc. Here’s an example:
const colors = require('tailwindcss/colors')

module.exports = {
  theme: {
    screens: {
      sm: '480px',
      md: '768px',
      lg: '976px',
      xl: '1440px',
    },
    colors: {
      gray: colors.coolGray,
      blue: colors.lightBlue,
      red: colors.rose,
      pink: colors.fuchsia,
    },
    fontFamily: {
      sans: ['Graphik', 'sans-serif'],
      serif: ['Merriweather', 'serif'],
    },
    extend: {
      spacing: {
        '128': '32rem',
        '144': '36rem',
      },
      borderRadius: {
        '4xl': '2rem',
      }
    }
  }
}

There are more options, but we will skip them as they are out of the current discussion. Our primary object is the theme section.

Let’s assume we get the following changes to be done in our form element:

  1. Update the colors as: #FF4F71(Rose red), #C40429 (Dark rose red) and #FBFBFB (Rose white).
  2. Change the font family to Kalam .
  3. Add two new border radii to be 1rem (base) and 5rem (bigger).
  4. The new spacings for margins or padding should be 1rem (base) and 1.5rem (bigger)

Now our task is to apply these changes to an existing React app. So where do we start? Yes, right inside the Tailwind config file!

We extend the theme option with the colors, fontFamily, extend and spacing objects and pass on the respective values.

  1. On the colors object we can define the three new colors we need by a reference name like roseRed (#FF4F71), darkRoseRed (#C40429) and roseWhite (#FBFBFB) along with their hex values. This will look like:
colors: {
    roseRed: '#FF4F71',
    darkRoseRed: '#C40429',
    roseWhite: '#FBFBFB',
},

Now whenever we like to use a specific color we can just use these names instead of the hex codes as a utility class for backgroundColor, borderColor, textColor, and others.

  1. Next, to use the new font family, we first need to get the @import from Google Fonts:
@import url('https://fonts.googleapis.com/css2?family=Kalam:wght@400;700&display=swap');

This should be added to the top of index.css below which we imported our Tailwind base styles. Then, we create a new fontFamily object as:

fontFamily: {
    fontHandwritten: 'Kalam',
},

Here we give the Kalam font an alternate name of fontHandwritten and we will be using this in our markup.

  1. To preserve the default values for a theme option and also to add new custom values, we can add all our extensions under the extend key of the theme object. We can do this to extend the border radius. Hence, we use the borderRadius object with the two values we got in the design change:
borderRadius: {
    borderBase: '1rem',
    borderBig: '5rem',
},
  1. And at last for the spacing of and between the elements we have the spacing key to customise global sizing scale:
spacing: {
    spaceNatural: '1rem',
    spaceNaturalPlus: '1.5rem',
},

Hence our entire tailwind.config.js file now looks like:

module.exports = {
 purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
 darkMode: false, // or 'media' or 'class'
 variants: {
   extend: {},
 },
 plugins: [],
 theme: {
   colors: {
     roseRed: '#FF4F71',
     darkRoseRed: '#C40429',
     roseWhite: '#FBFBFB',
   },
   fontFamily: {
     fontHandwritten: 'Kalam',
   },
   extend: {
     borderRadius: {
       borderBase: '1rem',
       borderBig: '5rem',
     },
   },
   spacing: {
     spaceNatural: '1rem',
     spaceNaturalPlus: '1.5rem',
   },
 },
};

Updating our markup

Now let’s stretch some legs and let’s update our JSX markup of the input form component to apply the latest changes in accordance to the configuration changes.

Head over to the app.js file and now we can use our custom utility classes as follows:

  1. On the <form> tag we add font-fontHandwritten which applies the Kalam font family to the entire form.

  2. The padding classes updates to p-spaceNatural for small padding values (1rem) and px-spaceNaturalPlus for bigger (1.5rem).

  3. Same goes for the margin value. We now have mr-spaceNatural instead of mr-2.

  4. As for the border and colors. To increase the new border radius according to our design system, we use rounded-borderBase in both the input and the button. Then, for the #C40429 colored border, we have border-darkRoseRed which we can also apply to the text inside the input with text-darkRoseRed.

  5. The button gets rounded-borderBig bg-roseRed hover:bg-darkRoseRed classes for the bigger rounded radius, red background color and a darker one while on hover respectively.

Here’s the entire code of the updated JSX markup:

import './App.css';

function App() {
 return (
   <div className='App text-lg' style={{ marginTop: '50%' }}>
     <form className='text-lg font-fontHandwritten'>
       <input
         className='p-spaceNatural mr-spaceNatural border rounded-borderBase border-darkRoseRed text-darkRoseRed outline-none'
         placeholder='Enter your mail'
       />
       <button className='py-spaceNatural px-spaceNaturalPlus rounded-borderBase text-roseWhite font-bold rounded-borderBig bg-roseRed hover:bg-darkRoseRed outline-none'>
         Sign up
       </button>
     </form>
   </div>
 );
}

export default App;

This will get you the desired result:

Demo of final design

Demo of final design

Conclusion

And there you go! You now have the same form element but with completely different styles that make it stand out from the usual Tailwind styles.

In this article, we went from understanding what Tailwind CSS is to how it helps front-end developers with its unique features like low-level utility classes with a quick demo on how to use them to style basic things like text.

Next, we started with building a simple form element with the default styling of Tailwind to get a gist of using it in our React app along with the setup and installation. Then we did a deep dive into the config file to configure it to match design system changes and updated our code with custom styling.

Thanks for reading!

Programming Javascript Web Development NodeJS TypeScript