Graduate Program KB


Tailwind CSS


Overview

  1. Introduction
  2. History
  3. Inspiration
  4. Pitfalls
  5. Benefits
  6. Configuration
  7. Directives
  8. Tools

Introduction

  • Tailwind CSS is a utility-first CSS framework
  • It provides thousands of pre-defined classes, no longer need to maintain custom CSS
  • Promotes consistency, efficiency and scalability
  • Used by many large companies such as Netflix and OpenAI (ChatGPT)
  • Easy to also append custom CSS for edge cases

History

  • Created by Adam Wathan in 2017, motivated by the unmaintainability of writing traditional CSS
  • Tailwind v2.1 introduced JIT compiler with the ability to purge unused CSS for minification
  • Currently in v3.4.13, purge is removed since it only generates the minimum CSS
  • In the future, v4.0 will release with Oxide (new engine), faster parsing, build times with a unified tool chain

Inspiration

  • As we know, styles are applied by adding class tags to the class attribute in HTML elements

  • Class names typically reflect the appearance of the component

    <div class='profile-card' />
    
    • However, we might want to reuse card looking components throughout a project
      • Instead, use general classes that can be reusable
    <div class='card' />
    
  • Issue: Each use case of a general class may be slightly different

    • Ex. one place might want a box-shadow, another place might want a border radius
  • Solution: Extract non-common CSS properties into their own class

    <div class='card card-rounded card-shadow'/>
    
    .card-rounded {
    border-radius: 30px;
    }
    
  • Notice how the extracted class only does one thing

  • Tailwind applies the concept of atomic CSS, creating small, single-purpose classes

    <div class='flex p-2 font-sans shadow-md rounded-xl' />
    

Pitfalls

  • Learn Tailwind syntax
  • Bloats the HTML structure with class tags, affecting readability
  • Hard to migrate to another CSS framework since your current CSS will be Tailwind-specific

Benefits

  • No new functional logic, simply add styles to class attributes
  • Rapid prototyping since Tailwind provides all the styling already
  • Consistent and maintainable
  • No overhead of additional CSS files
  • Minified build size by only generating used classes
  • Tailwind already attempts to normalise the experience between browsers through its base styles

Configuration

  • Optional tailwind.config.js at the root to apply customisations

  • To generate a template: npx tailwindcss init

    /** @type {import('tailwindcss').Config} */
    module.exports = {
    content: ["./src/**/*.{html,js}"],
    theme: {
        extend: {},
    },
    plugins: [],
    }
    

Generating classes

  • content specifies the location of source files to search for Tailwind class names so it can dynamically generate styles

  • Not limited to only searching the class attribute, you can toggle classes with JavaScript

    <p class="py-2 text-gray-600"
    Hello everyone
    /> 
    
    // Below is the list of strings that Tailwind will consider when scanning this file
    // p, class, py-2, text-gray-600, Hello, everyone
    
    const element = document.getElementById('p')
    element.classList.toggle('hidden')
    
  • When scanning files, Tailwind does not parse or execute code

  • Full class name must exist somewhere within the source file, it does not resolve partial strings

    // Wrong
    <div class="text-{{ error ? 'red' : 'green' }}-600">
    
    // Correct
    <div class="{{ error ? 'text-red-600' : 'text-green-600' }}">
    
    <p>
    It will find the class text-red-600 even in the content section.
    </p>
    
  • Referencing the previous code snippet, text-red-600 is not used in the context of styling but it will still be generated

  • blocklist property in the configuration can prevent these types of styles from generating

    <p>
    Do you want a container?
    </p>
    <p>
    I might collapse from exhaustion.
    </p>
    
    module.exports = {
    content: ["./src/**/*.{html,js}"],
    blocklist: ['container', 'collapse']
    }
    

Prefix option

  • prefix: Add a custom prefix to Tailwind's generated utility classes

  • ONLY added to Tailwind classes

  • Useful for separating CSS systems and custom CSS from Tailwind

    // tailwind.config.js
    
    module.exports = {
    prefix: 'tw-',
    ...
    }
    
    // index.html
    
    <h1 
    class="tw-text-blue-500 hover:tw-text-red-500"
    >
    </h1>
    

Themes option

  • themes: Extend / configure overridable values for pre-defined utility classes

    theme: {
    screens: {
        'sm': '700px', // Default: 640px
    },
    colors: {
        white: '#fff',
        gray: {
        100: '#f7fafc',
        // ...
        900: '#1a202c'
        }
    }
    }
    
  • Here's a scenario where a project's colour palette can be configured for easy application using the extend property

    theme: {
    extend: {
        colors: {
        'custom-1': '#ADD8E6',
        'custom-2': '#A2A8D3',
        'custom-3': '#38598B',
        'custom-4': '#113F67'
        }
    }
    }
    

Plugin option

  • Register new styles using JavaScript

  • plugin is imported from tailwindcss/plugin and provides an object containing helper functions to your callback function (custom plugin)

    // tailwind.config.js
    
    import plugin from 'tailwindcss/plugin'
    
    module.exports = {
    plugins: [
        plugin((objectWithUtils) => {})
    ]
    ...
    }
    

Static utilities example

plugins: [
plugin(function ({ addUtilities }) {
    const newUtilities = {
    '.text-shadow': {
        textShadow: '2px 2px rgba(0, 0, 0, 0.5)',
        },
    '.text-shadow-lg': {
        textShadow: '4px 4px rgba(0, 0, 0, 0.7)',
    },
    };
    
    addUtilities(newUtilities);
})
]

Dynamic utilities example

  • Generated classes:

    • margin-1: 0.25 rem
    • margin-2: 0.5 rem
    • margin-3: 0.75 rem
    • margin-4: 1 rem
    theme: {
    extend: {
        spacing: {
        '1': '0.25rem',
        '2': '0.5rem',
        '3': '0.75rem', 
        '4': '1rem', 
        },
    },
    }
    
    plugins: [
    plugin(function({ matchUtilities, theme }) {
        matchUtilities(
        {
            'margin': (value) => ({
            margin: value,
            }),
        },
        {
            values: theme('spacing'),
        }
        )
    }),
    ]
    

Directives

  • base: Resets styles to ensure consistency between browser engines

  • components: Inject Tailwind component classes or components registered by plugins

  • utilities: Adds utility classes for styling your HTML

  • layer: Tells Tailwind which "layer" a set of custom styles belong to (base, components, utilities)

  • apply: Allows you to inline Tailwind utility classes into custom CSS

    @tailwind base;
    @tailwind components;
    @tailwind utilities;
    
    @layer components {
    .custom-btn-blue {
        @apply bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded;
    }
    }
    

Generate final stylesheet

  • Input file contains directives and custom CSS
  • Output file contains generated CSS styles used by your project
  • npx tailwindcss -i [input.css] -o [output.css]

Tools

VSCode extension

  • Tailwind CSS IntelliSense
  • Adds quality of life features: autocomplete, syntax highlighting, linting

Prettier plugin

  • npm install prettier prettier-plugin-tailwindcss

  • Sorts class tags into related groups

  • Headwind is an alternative vscode extension that performs the same thing

    // .prettierrc
    
    {
    "plugins": ["prettier-plugin-tailwindcss"]
    }
    
  • Example of classes being sorted on save

    <button class="text-white px-4 sm:px-8 py-2 
                sm:py-3 bg-sky-700 hover:bg-sky-800"
    >
    </button>
    
    <button class="bg-sky-700 px-4 py-2 text-white 
                hover:bg-sky-800 sm:px-8 sm:py-3"
    >
    </button>