Explaining the Tailwind Config for Windy UI


In this post I will be explaining the Tailwind Config file and how it is set up for Windy UI.

This post assumes that you know how to do a basic Tailwind CSS setup. I’m not going to go through that here, but you can check how to do that here.

The installation must be done with PostCSS (which is the recommended installation for Tailwind anyway) since we need to customize the tailwind config more than a little bit for the components in Windy UI to work as expected.

The Setup

Base CSS file

You’ll first need a base CSS file. This file should be located in a separate folder. For the purposes of this walkthrough, we’ll be calling it “Styles”.

We are naming the file “site.css” but you can name it what you’d like. Following is the contents of said CSS file.

/*Use this section for the importing of fonts that you will use in your project.*/
/*Windy UI components are set to use two different fonts, but you can configure it to use the same font if you only use one.*/
@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Raleway:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;1,100;1,200;1,300;1,400;1,500&display=swap');
@tailwind base;
@tailwind components;
@tailwind utilities;

/*Styles for the Blazor error prompt when there is a runtime error.*/
#blazor-error-ui {
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 0.75rem;
    top: 0.5rem;
}

You’ll also need a postcss config file, which is the default one:

module.exports = {
    plugins: {
        tailwindcss: {},
        autoprefixer: {},
    }
}

Package.json

You’ll need a package.json file for this in the same folder with the installation for both Tailwind, PostCSS and the forms plugin.

The package.json file for the documentation looks something like this:

{
    "version": "1.0.0",
    "name": "windy-ui-documentation",
    "private": true,
    "scripts": {
        "buildcss": "postcss 'Styles/site.css' -o '../wwwroot/css/site.min.css'"
    },
    "devDependencies": {
        "@tailwindcss/forms": "^0.3.2",
        "autoprefixer": "^10.0.2",
        "postcss": "^8.2.1",
        "postcss-cli": "^8.3.1",
        "tailwindcss": "^2.1.2"
    }
}

You’ll see that the scripts in the package.json file include the command “buildcss”. Be mindful of your folder structure and the name of your CSS file since you’ll need to change this based the name and location of your file.

You’ll also see that we’re sending the output to the “wwwroot” folder. You’ll need to add the reference to the Tailwind CSS to the base HTML of your Blazor app for the styles to be applied.

You’ll notice as well that we haven’t mentioned the tailwind config file. This file is extremely important, but it needs to be digged into.

Tailwind Config

With all this said, we can start disecting the Tailwind config and why some things are necessary for the library to work.

Colors

Starting with colors, Windy UI uses 7 color types, 2 that you’ll likely modify a lot and 5 others which are contextual.

All can be modified freely. The color labels are:

  • Primary: Your primary branding color.
  • Secondary: Your secondary branding color.
  • Success: The color used for successful actions. Typically a green color.
  • Danger: Used for letting the user know the action is dangerous or otherwise irreversible.
  • Info: A color used to provide information without evoking a specific emotion.
  • Warning: Typically a yellow. Used to warn the user of a potentially unwanted action but with less potential damage than “Danger”.
  • Neutral: Usually a Grayscale color when such a color is necessary.

All colors have 4 variants that can be configured:

  • Default: The main color the label is represented by.
  • Text: The color used for text that is used in a default color background.
  • Light: A variant of the default color to provide accents to certain UI elements.
  • Dark: Darker variant of default. Used mostly to accent on certain UI elements.

With that in mind, we need to decide the colors to use in the project. The defaults for success, warning, danger, info and neutral will fit most scenarios, but you can use a tool such as Tailwind Ink to pick colors according to your desired branding for primary and secondary.

Here is the example used by Windy UI documentation:

colors: {
    primary: {
        text: 'white',
        light: customColors.pine['100'],
        DEFAULT: customColors.pine['400'],
        dark: customColors.pine['500']
    },
    secondary: {
        text: 'white',
        light: customColors.olive['200'],
        DEFAULT: customColors.olive['400'],
        dark: customColors.olive['500']
    },
    success: {
        text: 'white',
        light: colors.emerald['100'],
        DEFAULT: colors.emerald['600'],
        dark: colors.emerald['700']
    },
    danger: {
        text: 'white',
        light: colors.red['200'],
        DEFAULT: colors.red['600'],
        dark: colors.red['700']
    },
    info: {
        text: 'white',
        light: colors.lightBlue['200'],
        DEFAULT: colors.lightBlue['500'],
        dark: colors.lightBlue['700']
    },
    warning: {
        text: colors.gray['800'],
        light: colors.amber['200'],
        DEFAULT: colors.amber['300'],
        dark: colors.amber['500']
    },
    neutral: {
        text: colors.gray['100'],
        light: colors.gray['200'],
        DEFAULT: colors.gray['600'],
        dark: colors.gray['700']
    }
}

Fonts

Fonts are a very important part of any UI work. As such, the default components of Windy UI support two fonts that can be used in the typography components and also as utility classes.

  • Header
  • Body

The typography components utilize these explicitly and the documentation of Windy UI uses two fonts. If you wish to use just one font, nothing stops you from using the same font in the definition of both utility classes.

Also, since you have complete control over your tailwind config file, you can also add whatever fonts you need as separate utility classes, just know that these two are used internally in the default components.

The following example is the one being used in the Windy UI documentation.

fontFamily: {
    header: ["Montserrat"],
    body: ["Raleway"]
}

Animation

For animation we need to add 2 things to the Talwind config file, first, the keyframes for fade in and fade out animations, but also after that, some extra utility classes that are needed for the modal, snackbar and notification components.

Keyframes (For animations)

  • Fade In
  • Fade Out

We first define the keyframes and then we can handle the timing for the animation utility the timings required by the library are the following:

  • 300 ms
  • 400 ms
  • 500 ms

With this in mind, the section for this in the config is the following:

animation: {
    'fadein-500': "fadeIn 0.5s ease-in forwards",
    'fadein-400': "fadeIn 0.4s ease-in forwards",
    'fadein-300': "fadeIn 0.3s ease-in forwards",
    'fadeout-400': "fadeOut 0.4s ease-out forwards",
    'fadeout-300': "fadeOut 0.3s ease-out forwards",
    'fadeout-200': "fadeOut 0.2s ease-out forwards"
},
keyframes: {
    fadeIn: {
        "0%": { opacity: 0 },
        "100%": { opacity: 1 }
    },
    fadeOut: {
        "0%": { opacity: 1 },
        "100%": { opacity: 0 }
    }    
}

Plugins required

The only plugin required for now is the forms plugin which is already included in the package.json file above.

Final config

With all this said, the complete config file looks like this:

const colors = require('tailwindcss/colors');

//Generated with: https://tailwind.ink/
const customColors = {
    pine: {
        '50': '#eef5f5',
        '100': '#ceeff4',
        '200': '#97e5e6',
        '300': '#49d9e8',
        '400': '#26ada1',
        '500': '#1b927c',
        '600': '#187b63',
        '700': '#175e4e',
        '800': '#12413a',
        '900': '#0c282b',
    },
    olive: {
        '50': '#fbfaf4',
        '100': '#f8efbd',
        '200': '#f0dd83',
        '300': '#d9b951',
        '400': '#b98f2c',
        '500': '#9a7016',
        '600': '#7d560e',
        '700': '#60410d',
        '800': '#412d0b',
        '900': '#2c1c09',
    },
    seagreen: {
        '50': '#f3f6f4',
        '100': '#e0efea',
        '200': '#b9e4d1',
        '300': '#81c8a5',
        '400': '#3fa776',
        '500': '#2c8b4e',
        '600': '#26743a',
        '700': '#21582f',
        '800': '#183d24',
        '900': '#11261b',
    }
}

module.exports = {
    purge: [],
    darkMode: false, // At this moment, Windy UI components do not support dark mode.
    theme: {
        colors: {
            transparent: 'transparent',
            current: 'currentColor',
            black: colors.black,
            white: colors.white,
            gray: colors.coolGray,
            red: colors.red,
            yellow: colors.amber,
            green: colors.emerald,
            blue: colors.blue,
            indigo: colors.indigo,
            purple: colors.violet,
            pink: colors.pink,
        },
        extend: {
            colors: {
                primary: {
                    text: 'white',
                    light: customColors.pine['100'],
                    DEFAULT: customColors.pine['400'],
                    dark: customColors.pine['500']
                },
                secondary: {
                    text: 'white',
                    light: customColors.olive['200'],
                    DEFAULT: customColors.olive['400'],
                    dark: customColors.olive['500']
                },
                success: {
                    text: 'white',
                    light: colors.emerald['100'],
                    DEFAULT: colors.emerald['600'],
                    dark: colors.emerald['700']
                },
                danger: {
                    text: 'white',
                    light: colors.red['200'],
                    DEFAULT: colors.red['600'],
                    dark: colors.red['700']
                },
                info: {
                    text: 'white',
                    light: colors.lightBlue['200'],
                    DEFAULT: colors.lightBlue['500'],
                    dark: colors.lightBlue['700']
                },
                warning: {
                    text: colors.gray['800'],
                    light: colors.amber['200'],
                    DEFAULT: colors.amber['300'],
                    dark: colors.amber['500']
                },
                neutral: {
                    text: colors.gray['100'],
                    light: colors.gray['200'],
                    DEFAULT: colors.gray['600'],
                    dark: colors.gray['700']
                }
            },
            fontFamily: {
                header: ["Montserrat"],
                body: ["Raleway"]
            },
            animation: {
                'fadein-500': "fadeIn 0.5s ease-in forwards",
                'fadein-400': "fadeIn 0.4s ease-in forwards",
                'fadein-300': "fadeIn 0.3s ease-in forwards",
                'fadeout-400': "fadeOut 0.4s ease-out forwards",
                'fadeout-300': "fadeOut 0.3s ease-out forwards",
                'fadeout-200': "fadeOut 0.2s ease-out forwards"
            },
            keyframes: {
                fadeIn: {
                    "0%": { opacity: 0 },
                    "100%": { opacity: 1 }
                },
                fadeOut: {
                    "0%": { opacity: 1 },
                    "100%": { opacity: 0 }
                }
            }
        },
    },
    variants: {
        extend: {},
    },
    plugins: [
        require('@tailwindcss/forms')
    ],
}