A utility-first CSS framework for rapid UI development.

  • By Tailwind Labs
  • Last update: Dec 1, 2022
  • Comments: 16

Tailwind CSS Tailwind CSS

A utility-first CSS framework for rapidly building custom user interfaces.

Build Status Total Downloads Latest Release License


Documentation

For full documentation, visit tailwindcss.com.

Community

For help, discussion about best practices, or any other conversation that would benefit from being searchable:

Discuss Tailwind CSS on GitHub

For casual chit-chat with others using the framework:

Join the Tailwind CSS Discord Server

Contributing

If you're interested in contributing to Tailwind CSS, please read our contributing docs before submitting a pull request.

Github

https://github.com/tailwindlabs/tailwindcss

Comments(16)

  • 1

    TypeError: getProcessedPlugins is not a function

    Describe the problem:

    Upgraded from TailwindCSS 1.9.6 to 2.0.1 for my angular project following the instructions on their website. I had previously used the following guide: https://notiz.dev/blog/angular-10-with-tailwindcss#setup to Install the previous version and that worked before.

    Please see error below:

    ERROR in Module build failed (from ./node_modules/postcss-loader/dist/cjs.js):
    TypeError: getProcessedPlugins is not a function
        at /home/greg/angular-website/frontend/node_modules/tailwindcss/lib/processTailwindFeatures.js:71:83
        at LazyResult.runOnRoot (/home/greg/angular-website/frontend/node_modules/postcss/lib/lazy-result.js:276:16)
        at LazyResult.runAsync (/home/greg/angular-website/frontend/node_modules/postcss/lib/lazy-result.js:328:26)
        at async Object.loader (/home/greg/angular-website/frontend/node_modules/postcss-loader/dist/index.js:94:14)
    
    ERROR in ./src/styles.scss (./node_modules/css-loader/dist/cjs.js??ref--13-1!./node_modules/@angular-devkit/build-angular/node_modules/postcss-loader/src??embedded!./node_modules/resolve-url-loader??ref--13-3!./node_modules/sass-loader/dist/cjs.js??ref--13-4!./node_modules/postcss-loader/dist/cjs.js??ref--17!./src/styles.scss)
    Module build failed (from ./node_modules/postcss-loader/dist/cjs.js):
    TypeError: getProcessedPlugins is not a function
        at /home/greg/angular-website/frontend/node_modules/tailwindcss/lib/processTailwindFeatures.js:71:83
        at LazyResult.runOnRoot (/home/greg/angular-website/frontend/node_modules/postcss/lib/lazy-result.js:276:16)
        at LazyResult.runAsync (/home/greg/angular-website/frontend/node_modules/postcss/lib/lazy-result.js:328:26)
        at async Object.loader (/home/greg/angular-website/frontend/node_modules/postcss-loader/dist/index.js:94:14)
    
    
  • 2

    Custom class name completion contexts

    There has been quite a few requests for the extension to support class name completions in contexts other than a standard class(Name) attribute.

    Some examples:

    I just wanted to consolidate all of these requests into a single issue that can be tracked more easily, as I think the solution could be the same for each of them.

    I am reluctant to hard-code each of these cases into the extension because none of them are "official" methods of using Tailwind, and it may become a maintenance burden.

    However, I am open to the idea of adding a user setting which would allow the definition of custom regular expressions. For example for tailwind-rn your regular expression might be something like: /\btailwind\([^)]+/ig

    If you're interested in this feature feel free to "watch" this issue for updates, and post any comments/suggestions you may have.

  • 3

    Add CSS Grid utilities

    This PR adds support for CSS Grid Layout to Tailwind CSS.

    Here is an example of what it looks like to use these new utilities:

    <div class="grid grid-cols-8 col-gap-6 row-gap-6">
      <div class="col-span-3"></div>
      <div class="col-span-3"></div>
      <div class="col-start-4 col-end-8"></div>
      <div class="col-span-4 col-start-2"></div>
      <div class="col-span-6 col-end-9"></div>
    </div>
    

    It adds a new grid value to the display core plugin, as well as provides new core plugins for the following CSS properties:

    • grid-template-columns
    • grid-column-gap
    • grid-column
    • grid-column-start
    • grid-column-end
    • grid-template-rows
    • grid-row-gap
    • grid-row
    • grid-row-start
    • grid-row-end

    grid-template-columns

    These utilities take the form grid-cols-{key} where "key" is any value configured under the gridTemplateColumns key in your theme config.

    By default we provide the necessary values to create basic equal width column grids with up to 12 columns:

    gridTemplateColumns: {
      '1': 'repeat(1, 1fr)',
      '2': 'repeat(2, 1fr)',
      '3': 'repeat(3, 1fr)',
      '4': 'repeat(4, 1fr)',
      '5': 'repeat(5, 1fr)',
      '6': 'repeat(6, 1fr)',
      '7': 'repeat(7, 1fr)',
      '8': 'repeat(8, 1fr)',
      '9': 'repeat(9, 1fr)',
      '10': 'repeat(10, 1fr)',
      '11': 'repeat(11, 1fr)',
      '12': 'repeat(12, 1fr)',
    }
    

    I've opted to avoid any weird magic here and instead just given the user complete control over the value of this property, so although I'm just using repeat(x, 1fr) here for each value, there's absolutely nothing stopping you from creating something more custom like so:

    gridTemplateColumns: {
      // Would create a class called `grid-cols-header`
      'header': '100px minmax(min-content, 600px) 1fr',
    }
    

    Providing a basic 12 column grid seemed like the most sensible thing to do by default, as there aren't many other good ideas I can think of that are actually general purpose and not hyper-specific to one site design.

    grid-column-gap

    These utilities take the form col-gap-{key} where "key" is any value configured under the gridColumnGap key in your theme config.

    By default, this uses your spacing config, and therefore matches all of your padding/margin/width/height utilities.

    grid-column

    These utilities take the form col-{key} where "key" is any value configured under the gridColumn key in your theme config.

    By default we only provide values for spanning across columns:

    gridColumn: {
      'span-1': 'span 1 / span 1',
      'span-2': 'span 2 / span 2',
      'span-3': 'span 3 / span 3',
      'span-4': 'span 4 / span 4',
      'span-5': 'span 5 / span 5',
      'span-6': 'span 6 / span 6',
      'span-7': 'span 7 / span 7',
      'span-8': 'span 8 / span 8',
      'span-9': 'span 9 / span 9',
      'span-10': 'span 10 / span 10',
      'span-11': 'span 11 / span 11',
      'span-12': 'span 12 / span 12',
    }
    

    Again no magic or assumptions here at all — I've included the word span explicitly in each key to make sure the utilities are generated like col-span-5 for our default values, but you can totally do whatever you want here, like:

    gridColumn: {
      'logo-area': 'my-logo-area-label',
    }
    

    ...to generate a class that fills a named column area like col-logo-area.

    The reason I've duplicated the value (like span 2 / span 2) is so that you can easily override just the grid-column-start or grid-column-end value without losing the span value, like this:

    <div class="col-span-4 col-start-2"></div>
    

    ...which would create an element that spans 4 columns but starts at grid line 2.

    grid-column-start

    These utilities take the form col-start-{key} where "key" is any value configured under the gridColumnStart key in your theme config.

    By default we only provide values that match the grid lines created by our default gridTemplateColumns config:

    gridColumnStart: {
      '1': '1',
      '2': '2',
      '3': '3',
      '4': '4',
      '5': '5',
      '6': '6',
      '7': '7',
      '8': '8',
      '9': '9',
      '10': '10',
      '11': '11',
      '12': '12',
      '13': '13',
    },
    

    grid-column-end

    These utilities take the form col-end-{key} where "key" is any value configured under the gridColumnEnd key in your theme config.

    By default we only provide values that match the grid lines created by our default gridTemplateColumns config:

    gridColumnEnd: {
      '1': '1',
      '2': '2',
      '3': '3',
      '4': '4',
      '5': '5',
      '6': '6',
      '7': '7',
      '8': '8',
      '9': '9',
      '10': '10',
      '11': '11',
      '12': '12',
      '13': '13',
    },
    

    grid-template-rows

    These utilities take the form grid-rows-{key} where "key" is any value configured under the gridTemplateRows key in your theme config.

    By default we do not provide any values for this utility at all:

    gridTemplateRows: {}
    

    That means no grid-rows-{key} utilities are generated by default, and if you'd like to add them you need to customize your config.

    This is because I just could not think of any sensible general purpose default values for this — any real-world use case I could come up with seemed too specific to a given design.

    grid-row-gap

    These utilities take the form row-gap-{key} where "key" is any value configured under the gridRowGap key in your theme config.

    By default, this uses your spacing config, and therefore matches all of your padding/margin/width/height utilities.

    grid-row

    These utilities take the form row-{key} where "key" is any value configured under the gridRow key in your theme config.

    By default we do not provide any values for this utility at all:

    gridRow: {}
    

    That means no row-{key} utilities are generated by default, and if you'd like to add them you need to customize your config.

    This is for the same reason as grid-template-rows.

    grid-row-start

    These utilities take the form row-start-{key} where "key" is any value configured under the gridRowStart key in your theme config.

    By default we do not provide any values for this utility at all:

    gridRowStart: {}
    

    That means no row-start-{key} utilities are generated by default, and if you'd like to add them you need to customize your config.

    This is for the same reason as grid-template-rows.

    grid-row-end

    These utilities take the form row-end-{key} where "key" is any value configured under the gridRowEnd key in your theme config.

    By default we do not provide any values for this utility at all:

    gridRowEnd: {}
    

    That means no row-end-{key} utilities are generated by default, and if you'd like to add them you need to customize your config.

    This is for the same reason as grid-template-rows.

    What's not included

    • grid-auto-columns utilities
    • grid-auto-rows utilities
    • grid-auto-flow utilities
    • grid-template-areas utilities

    If you think any of these are super important in a utility context, please reply with a good example and any ideas you have on how it should be included and we can definitely talk about getting it in.

    Try it out

    Here's a simple tailwind.run where I've thrown in the pre-compiled CSS so you can play with it:

    https://tailwind.run/MSuVJB/1

    Any feedback appreciated!

  • 4

    Tailwind CSS v1.0 To-Dos

    Have been keeping track of this stuff in my personal to-do tracker but publishing them here in case anyone is interested.

    Naturally a ton of stuff has already been done for v1.0 and deleted from my to-do list, so this is only the stuff remaining as of today.

    Expect this list to grow and change over the next few weeks as I work towards finishing v1.0, but generally these are the things I've got lined up. They aren't in any sort of priority order or anything.

    Done/Merged

    • [x] Re-evaluate flex-grow/flex-no-grow, etc.
    • [x] Re-assess using postcss-selector-parser for escaping
    • [x] Update plugins to source their config from theme/variants
    • [x] Think about if there's a smarter way to make sure the separator is escaped
    • [ ] ~~Pass theme and variants to plugins explicitly?~~ No measurable benefit, easy to add later
    • [x] Add new shadows
    • [x] Rename config function to theme?
    • [x] Fix letterSpacing classes not being escaped
    • [x] Add 56 as a width?
    • [x] Add extended widths (48, 56, 64) to entire spacing scale?
    • [x] Make flex-* customizable
    • [ ] ~~Remove .clearfix?~~ Nah still useful enough to not make people add it themselves.
    • [x] Add new maxWidth scale
    • [x] Revisit which variants to enable by default for split up text style plugins
    • [x] Make preflight more hardcore, reset headings, etc.
    • [x] Autodetect presence of tailwind.config.js?
    • [ ] ~~Headings should inherit line-height like they inherit font-size and font-weight.~~ Not necessary, browser inherits line-height already for headings.
    • [x] Inherit font-related properties on form controls by default (line-height, font-family, color, maybe others, see sanitize.css for ideas)
    • [x] Use line-height: 1.5 on body or html by default (why not? I never want 1.15 and we set that 🤷‍♂️)
    • [x] Use system font stack by default instead of "sans-serif", I literally never want that either
    • [x] Use fontFamily.mono for pre/code if possible, fall back to monospaced (beware double monospace thing)
    • [x] Add text-6xl? 64px?
    • [x] Add new default color palette
    • [x] Bump sm breakpoint up to 640px?
    • [x] Inherit color and text-decoration on links
    • [x] Reconsider lists core plugin, maybe handle list style only and not padding
    • [ ] ~~Re-evaluate truncate, possibly replace with ellipsis-only utility~~ Class is convenient and useful, could still add ellipsis utility separately though
    • [x] Consider making break-normal handle both properties to provide a nicer experience
    • [x] Get rid of pin utilities in favor of top/right/bottom/left/inset? Unsure if worth break.
    • [x] Consider if container should become a true core plugin instead of an included third-party plugin
    • [x] Split whitespace plugin into whitespace and wordBreak/wordWrap?
    • [x] Rework CLI for new config structure
    • [x] Make sure shadow-outline matches new blue
    • [ ] ~~Error if we find @tailwind preflight in your CSS or keys in the wrong place in your config file to help guide people during the upgrade process?~~ Whatever, can do this if it actually bites people.
    • [ ] ~~Consider if defaultConfig/defaultTheme need to be separate files or even importable? Maybe make it possible to export a function from your config, and we just pass you the defaults?~~ Will keep these exports for now, we could add function syntax later if it feels like a slicker solution since it is non-breaking
    • [x] Make img, canvas, video, etc. block by default, and constrain max width?
    • [ ] ~~Make utilities important by default? I always do this on my own projects~~ Easy to tweak yourself and it's nice that inline-styles override utilities if they aren't important
    • [x] Maybe pass theme function to config callbacks?
    • [ ] Consider trying to make form elements more consistent by default across browsers? BuzzFeed Solid framework pretty good reference for super vanilla looking forms.
    • [x] Fix theme('negativeMargin.5') sort of stuff, maybe by negating all values in the default config in the callback
    • [x] Write upgrade guide
    • [x] Write function/tool to upgrade 0.x config files

    PR Opened

    • [ ] Consider removing border radius on inputs because of the iOS crap, and fixing radio buttons with just a [type="radio"] selector to keep specificity down

    Next (painful)

    Next (straightforward)

    • [ ] Make sure shadow-inset doesn't suck
    • [ ] Update the docs

    Next (could wait until after 1.0)

    • [ ] Add sanity test for a heavily customized config
    • [ ] Allow specifying a base config to extend (extends root level key)
    • [ ] Add disabled variant?
    • [ ] Pass parseSelector to plugins?
  • 5

    Tailwind 2.0 poor performance as part of a webpack PostCSS build system

    Description of the problem

    Tailwind CSS 2.0 builds slowly as part of a HMR webpack build system. It is slower than the release, but that could just be due to the amount of CSS generated increasing.

    I filed a very similar issue a month ago https://github.com/tailwindlabs/tailwindcss/issues/2544 and worked around the problem by splitting the CSS up into separate chunks. Global @apply still worked, and everything was great.

    It's all written up in the article Speeding Up Tailwind CSS Builds

    However with Tailwind CSS 2.0, the technique described in the article breaks.

    Desired solution

    I'm hoping to have the DX of working with Tailwind CSS 2.0 be improved from a HMR build time perspective.

    I realize that you can only optimize your generation of CSS so much, and a PR is in the works to do just that with esbuild. I also realize that part of the slowness here is simply webpack and the surrounding ecosystem being slow when dealing with massive amounts of CSS (though I've optimized that quite a bit here).

    However, the paradigm that Tailwind CSS is using is what generates a massive amount of CSS, and webpack is a very widely used tool that many things are built upon.

    Some way to address the DX here would be great; huge gains can be made using the CSS splitting technique described in the article, maybe there could be a way to restore that functionality to Tailwind 2.x?

    Link to a minimal reproduction:

    I made a new branch with Tailwind 2.0, webpack 5, PostCSS 8, and all the goodness:

    https://github.com/nystudio107/tailwind-css-performance/tree/problem-tailwind-2.x

    webpack_1  | ℹ 「wdm」: Compiled successfully.
    webpack_1  | ℹ 「wdm」: Compiling...
    webpack_1  | ℹ 「wdm」: assets by status 72.8 KiB [cached] 2 assets
    webpack_1  | assets by status 9.21 MiB [emitted]
    webpack_1  |   assets by info 3.62 MiB [immutable]
    webpack_1  |     asset app.53801fed2ee43ce850f5.hot-update.js 3.62 MiB [emitted] [immutable] [hmr] (name: app)
    webpack_1  |     asset runtime.53801fed2ee43ce850f5.hot-update.js 881 bytes [emitted] [immutable] [hmr] (name: runtime)
    webpack_1  |     asset 53801fed2ee43ce850f5.hot-update.json 37 bytes [emitted] [immutable] [hmr]
    webpack_1  |   assets by path js/*.js 5.6 MiB
    webpack_1  |     asset js/app.js 5.55 MiB [emitted] (name: app)
    webpack_1  |     asset js/runtime.js 43.9 KiB [emitted] (name: runtime)
    webpack_1  |   asset manifest.json 303 bytes [emitted]
    webpack_1  | Entrypoint app 9.21 MiB = js/runtime.js 43.9 KiB runtime.53801fed2ee43ce850f5.hot-update.js 881 bytes js/app.js 5.55 MiB app.53801fed2ee43ce850f5.hot-update.js 3.62 MiB
    webpack_1  | cached modules 711 KiB [cached] 61 modules
    webpack_1  | runtime modules 28.9 KiB 14 modules
    webpack_1  | ./node_modules/css-loader/dist/cjs.js??clonedRuleSet-4.use[1]!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-4.use[2]!../src/css/app.pcss 3.61 MiB [built] [code generated]
    webpack_1  | example-project (webpack 5.4.0) compiled successfully in 2527 ms
    

    While 2.5s isn't awful, this is in a pretty minimal CSS setup, where I was getting about 1.2s for the equivalent builds in Tailwind 1.x, and using the technique described in the article, the builds were around 182ms

  • 6

    Integrate PurgeCSS directly into Tailwind

    This PR adds a new purge config option for purging unused CSS directly from within Tailwind instead of having to pull in and configure PurgeCSS manually.

    The API is much more opinionated and slimmed down by default, optimizing for the 95% use case:

    // tailwind.config.js
    module.exports = {
      purge: [
        './src/**/*.html',
        './src/**/*.html',
      ],
      theme: {},
      variants: {},
      plugins: [],
    }
    

    The purge option accepts an array of filenames/globs to scan for classes, and that's it. This should be enough for most people, but if you are one of those people who just can't help themselves and has to fiddle with everything, you can fine-tune the configuration however you like (keep reading for more on that).

    Things to note:

    • This option is only enabled when NODE_ENV is production. If you want to enable it explicitly based on some other conditional logic, you can use an object syntax and the enabled property, and specify your templates using the content property:

      // tailwind.config.js
      module.exports = {
        purge: {
          enabled: true,
          content: ['./src/**/*.html'],
        },
        // ...
      }
      
    • Only components and utilities are purged by default. Our base styles are not purged, and no custom CSS authored in your CSS files is purged, including any imports to outside libraries.

      This is to make sure you don't accidentally run into common pitfalls, like forgetting to scan your root HTML template (which is difficult with frameworks like Next.js since it is buried in node_modules) or accidentally purging styles that come from whatever datepicker library you've pulled in as an npm dependency.

      This means we are not purging absolutely everything that could be safely purged, but you get 99% of the benefit with much less manual tuning. You will basically never need to whitelist anything using this approach.

      Essentially we make your CSS file look like this:

      /* purgecss start ignore */
      @tailwind base;
      
      /* purgecss end ignore */
      @tailwind components;
      /* purgecss start ignore */
      
      .btn {
        @apply bg-blue-500 px-4 py-2 text-white;
      }
      
      .alert {
        @apply border p-4 rounded;
      }
      
      /* purgecss end ignore */
      @tailwind utilities;
      /* purgecss start ignore */
      
      .custom-utility {
        foo: bar;
      }
      /* purgecss end ignore */
      

      If you really want to purge everything, you can do so using mode: 'all':

      // tailwind.config.js
      module.exports = {
        purge: {
          mode: 'all',
          content: ['./src/**/*.html'],
        },
        // ...
      }
      

      You're much more likely to accidentally remove important styles if you do this but I'm not the cops — if it tickles your pickle go for it.

    • We are using a new extractor strategy that tries to be as permissive as possible.

      Here is the new extractor we're using:

      defaultExtractor: content => {
        // Capture as liberally as possible, including things like `h-(screen-1.5)`
        const broadMatches = content.match(/[^<>"'`\s]*[^<>"'`\s:]/g) || []
      
        // Capture classes within other delimiters like .block(class="w-1/2") in Pug
        const innerMatches = content.match(/[^<>"'`\s.()]*[^<>"'`\s.():]/g) || []
      
        return broadMatches.concat(innerMatches)
      }
      

      ...and here is the sample HTML we test our purging against:

      <!-- Basic HTML -->
      <div class="bg-red-500 md:bg-blue-300 w-1/2"></div>
      
      <!-- Vue dynamic classes -->
      <span :class="{ block: enabled, 'md:flow-root': !enabled }"></span>
      
      <!-- JSX with template strings -->
      <script>
        function Component() {
          return <div class={`h-screen`}></div>
        }
      </script>
      
      <!-- Custom classes with really weird characters -->
      <div class="min-h-(screen-4) bg-black! font-%#[email protected] w-(1/2+8)"></div>
      
      <!-- Pug -->
      span.inline-grid.grid-cols-3(class="px-1.5")
        .col-span-2
          Hello
        .col-span-1.text-center
          World!
      

      It works really well and I would be pretty surprised if you ever needed to customize this.

    If you want more control than what we offer, you can pass any options you want directly to PurgeCSS using the options property:

    // tailwind.config.js
    module.exports = {
      purge: {
        enabled: true,
        content: ['./src/**/*.html'],
    
        // These options are passed through directly to PurgeCSS
        options: {
          whitelist: ['bg-red-500', 'px-4'],
        }
      },
      // ...
    }
    

    Any options passed to PurgeCSS will override our own options, so for example if you pass content it will override our content property at the top-level.

    Happy purging 🤮

  • 7

    npx tailwindcss init not working

    Describe the problem:

    Using tailwind in post-css compatibility mode

    I've got tailwind 2.0 installed and the build process runs, however now I want to set up a config file so I can add custom colors etcetera. I run the npx tailwindcss init command and it fails with this output.

    λ npx tailwindcss init
    npx: installed 86 in 8.321s
    Cannot find module 'autoprefixer'
    

    I can see autoprefix in both package.json "autoprefixer": "^9.8.6", and the autoprefixer folder in the node_modules folder.

    Not sure how to resolve this, please advise.

  • 8

    CSS Transitions

    This PR introduces a handful of CSS transition utilities. See the discussion at https://github.com/tailwindcss/tailwindcss/issues/14. It's mostly just a few new generators and updated docs/tests/etc, but it also includes a fix to the variants-and-disabling partial that allows for no variants.

    • [x] Generators
    • [x] Config
    • [ ] Docs
    • [x] Tests
  • 9

    Dev server must be restarted to have classes applied with Snowpack

    What version of @tailwindcss/jit are you using?

    0.1.4

    What version of Node.js are you using?

    14.2.0

    What browser are you using?

    Chrome

    What operating system are you using?

    macOS

    Reproduction repository

    https://www.youtube.com/watch?v=G6d-SXdcJXs

    Hi there ☺️

    I tried to use this new JIT feature with a new React app built with Snowpack. Unfortunately, I cannot have Snowpack use Tailwind JIT properly.

    I think I might have missed something about the configuration process. When changing a class in a component, I have to stop and restart the dev server. Here are my config files:

    // snowpack.config.js
    module.exports = {
      mount: {
        public: { url: '/', static: true },
        src: { url: '/dist' },
      },
      plugins: [
        '@snowpack/plugin-react-refresh',
        '@snowpack/plugin-dotenv',
        '@snowpack/plugin-typescript',
        '@snowpack/plugin-postcss',
      ],
      routes: [{ match: 'routes', src: '.*', dest: '/index.html' }],
      optimize: {},
      packageOptions: {},
      devOptions: {},
      buildOptions: {},
    }
    
    // tailwind.config.js
    module.exports = {
      purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
      darkMode: false,
      theme: {
        extend: {},
      },
      variants: {
        extend: {},
      },
      plugins: [],
    }
    
    // postcss.config.js
    module.exports = {
      plugins: {
        '@tailwindcss/jit': {},
        autoprefixer: {},
      },
    }
    
    

    Thanks!

  • 10

    Poor performance as part of a webpack PostCSS build system

    Using the latest Tailwind CSS (1.8.13 as of this writing), I'm seeing slowness very similar to https://github.com/tailwindlabs/tailwindcss/issues/1620 & also https://github.com/tailwindlabs/tailwindcss/issues/443, the performance of using HMR with webpack-dev-server and webpack 4 or 5 is quite slow.

    It takes about 10 seconds on my MacBook Pro 2019 just changing a single color in a .pcss file, and it appears externally that it's rebuilding everything each time. The building of Tailwind CSS seems to have gotten slower and slower as the amount of utilities it includes have gone up.

    I'm not sure what the caching implemented in 1.7.2 does, but in a long running process (and maybe it's already doing this but) what if all of the Tailwind-specific imports like:

    @import "tailwindcss/base";
    

    ...were cached in a long running process, so it just returns the pre-generated blob? I'd imagine you're probably already doing this, but have any instrumentation or profiling been hooked up to the build to determine where the bottlenecks are?

    My postcss.config.js looks like this:

    module.exports = {
        plugins: [
            require('postcss-import')({
                plugins: [
                ],
                path: ['./node_modules'],
            }),
            require('tailwindcss')('./tailwind.config.js'),
            require('postcss-preset-env')({
                autoprefixer: { },
                features: {
                    'nesting-rules': true
                }
            })
        ]
    };
    

    ...and the whole setup is essentially what's here: https://nystudio107.com/blog/an-annotated-webpack-4-config-for-frontend-web-development#tailwind-css-post-css-config

    It's not doing anything fancy re: the PostCSS part of the build, but its extremely slow compared to the HRM of JavaScript modules, etc.

    I tried removing postcss-preset-env to see if it made a difference, but it doesn't seem to.

    Related: https://stackoverflow.com/questions/63718438/webpack-dev-server-slow-compile-on-css-change-with-tailwind

  • 11

    Transient read failure may cause permanent failure to watch file

    V3.1.18 Tailwind CLI, Visual Studio 2022 as editor. Node v14.18.1 Chrome Window 10 (No Docker or WSL)

    This issue is a very close relative of #7759, but I think it might be quite specialised so I don't want to pollute that one.

    I have a rather odd web project, which has a single HTML file. So the content section of tailwind.config.js looks like this:

      content: [
          "./wwwroot/index.html"
      ],
    

    I run a tailwind CLI watcher with a command like this:

    npx tailwindcss --output wwwroot/css/tailwind.css --watch -i css/twbase.css
    

    I am suffering from the problem described in #7759 where the watcher stops watching after a while - anywhere between almost immediately and after lots and lots of successful rebuilds.

    By using the "Process Monitor" utility to observe the filesystem activity on the index.html file, I have observed that when Visual Studio (devenv.exe) is saving index.html, it goes through a rename/replace process which means there is a window of time in which the index.html file does not actually exist. It appears that node.exe (i.e. Tailwind) sometimes tries to read the file during this window and finds it to be missing.

    This apparently causes Tailwind to stop watching that file.

    image

    The blue selected line in the image is Node getting a file-not-found failure doing a CreateFile (it's actually an open-to-read) on index.html in the middle of devenv doing a rename dance. I think that's a smoking gun.

    If I change the content file specification to be a wildcard, then my first impression is that things are much more robust:

      content: [
          "./wwwroot/*.html"
      ],
    

    So:

    1. Is it possible/likely that TW is converting a transient read-failure on a watched file into a permanent failure to watch that file?
    2. If so, could this be fixed?

    Even without the specific Visual Studio rename thing, transient read failures are probably an inescapable feature of Windows, because it's so common that people have tools like anti-virus and cloud-backup and indexers which do lots of automatic file opening.

  • 12

    Update postcss-selector-parser: 6.0.10 → 6.0.11 (patch)

    Here is everything you need to know about this update. Please take a good look at what changed and the test results before merging this pull request.

    What changed?

    ✳️ postcss-selector-parser (6.0.10 → 6.0.11) · Repo · Changelog

    Release Notes

    6.0.11

    6.0.11

    • Fixed: parse attribute case insensitivity flag

    Does any of this look wrong? Please let us know.

    Commits

    See the full diff on Github. The new version differs by 3 commits:


    Depfu Status

    Depfu will automatically keep this PR conflict-free, as long as you don't add any commits to this branch yourself. You can also trigger a rebase manually by commenting with @depfu rebase.

    All Depfu comment commands
    @​depfu rebase
    Rebases against your default branch and redoes this update
    @​depfu recreate
    Recreates this PR, overwriting any edits that you've made to it
    @​depfu merge
    Merges this PR once your tests are passing and conflicts are resolved
    @​depfu close
    Closes this PR and deletes the branch
    @​depfu reopen
    Restores the branch and reopens this PR (if it's closed)
    @​depfu pause
    Ignores all future updates for this dependency and closes this PR
    @​depfu pause [minor|major]
    Ignores all future minor/major updates for this dependency and closes this PR
    @​depfu resume
    Future versions of this dependency will create PRs again (leaves this PR as is)
  • 13

    resolveConfig returns wrong TypeScript type for theme keys

    What version of Tailwind CSS are you using?

    3.2.4

    What build tool (or framework if it abstracts the build tool) are you using?

    Vite 3.2.4

    What version of Node.js are you using?

    16.18.1

    What browser are you using?

    N/A

    What operating system are you using?

    Linux

    Reproduction URL

    Repro on CodeSandbox (may take a second or click in the editor for the IDE to pick up the type issue)

    Describe your issue

    Using the recently exposed resolveConfig types, many config keys (such as theme.colors) throw TS errors:

    Unresolved config key type

    ResolvableTo<T> is an internal type that equals T | ((utils: PluginUtils) => T) - presumably a type that gets resolved during resolveConfig. The expected colour key (gray, in this case) doesn't exist on the function type, causing the issue. I suspect the resolved config should return the expected RecursiveKeyValuePair type with ResolvableTo removed.

  • 14

    Arbitrary values aren't recognised in Ruby percent arrays

    Thank you for an awesome tool! I've been using it in all my projects recently and the productivity gains have been immense.

    What version of Tailwind CSS are you using?

    Tailwind v3.2.4

    What build tool (or framework if it abstracts the build tool) are you using?

    postcss: 8.4.19, postcss-cli 10.0.0

    What version of Node.js are you using?

    Node v16.18.1

    What browser are you using?

    Firefox

    What operating system are you using?

    macOS

    Reproduction URL

    I have added a test case that fails, showing the incorrect behaviour. This is the first time I've popped the hood on Tailwind, so forgive me if the regexes I've linked are the incorrect ones.

    https://github.com/developius/tailwindcss/commit/5fb86ab84603949212d8146b09d242b420c7df85

    Describe your issue

    We're using Ruby on Rails with Tailwind and use the Ruby percent string syntax to generate arrays. Something like %w[text-[#bada55]] becomes ["text-[#bada55]"] in Ruby.

    The following ERB code doesn't correctly generate the arbitrary value Tailwind class:

    <%= content_tag(:div, class: %w[text-[#bada55]]) {} %>
    

    However, this does work:

    <%= content_tag(:div, class: ["text-[#a55bad]"]) {} %>
    

    As noted in my commit above, I think this is due to the extra closing square bracket tripping up the regex here^1 but my knowledge of Tailwind's internals is very vague.

    I'm not sure if there's a way to fix this or not, as I appreciate that handling extremely specific scenarios like this is a direction the project might not want to head in. But maybe there's a quick fix? Thanks for checking this issue out, anyway 😄

  • 15

    --watch doesn't work in background

    What version of Tailwind CSS are you using?

    v3.2.4

    What build tool (or framework if it abstracts the build tool) are you using?

    TailwindCSS standalone binary

    What operating system are you using?

    Happens on both Linux and Windows

    Describe your issue

    I have a shell script to start my development server:

    #!/bin/env bash
    
    # Get absolute path to project's root direcotry
    PROJECT_ROOT=$(realpath "$0")
    PROJECT_ROOT=$(dirname "$PROJECT_ROOT")
    
    # Run tailwind watcher in background
    ${PROJECT_ROOT}/tailwind/tailwind_bin_v3.2.4 \
    --watch \
    --config ${PROJECT_ROOT}/tailwind/config.js \
    --input ${PROJECT_ROOT}/tailwind/main.css \
    --output ${PROJECT_ROOT}/app/static/css/tailwind.css &
    
    # Run flask dev server in debug mode
    flask --debug run
    

    This worked perfectly fine with TailwindCSS v3.1.8 but now I upgraded to v3.2.4 and it doens't work anymore.

    Downgrading to v3.1.8 makes it work again.

    Expected behaviour

    When running the script, the Tailwind watcher should run as a background process and I should see its output (Rebuilding...Done in 267ms) in stdout.

    Actual behaviour

    The Tailwind watcher doesn't run and I can't see any output in stdout.

    Note

    When running the command in foreground (without & at the end) it works as expected. So as a workaround I run flask in background and tailwind in foreground.

  • 16

    Subtraction in `calc()` arbitrary values not always normalized properly

    What version of Tailwind CSS are you using?

    v3.2.4

    What build tool (or framework if it abstracts the build tool) are you using?

    Tailwind Play, Webpack v5

    What version of Node.js are you using?

    v16.13.0

    What browser are you using?

    Chrome

    What operating system are you using?

    Ubuntu 18.04 via WSL

    Reproduction URL

    https://play.tailwindcss.com/KnpyuskR45

    Describe your issue

    A value like calc(1-(var(--something)*0.5)) or calc(1-var(--something)*0.5) in an arbitrary variant is not normalized properly, with spaces missing around the subtraction operator:

    .mt-\[calc\(1-var\(--something\)\*0\.5\)\] {
      margin-top: calc(1-var(--something) * 0.5);
      /* expected margin-top: calc(1 - var(--something) * 0.5); */
    }
    

    I would have expected this function consistently akin to the other mathematical operators which seem to be fine:

    .mt-\[calc\(1\+\(var\(--something\)\*0\.5\)\)\] {
      margin-top: calc(1 + (var(--something) * 0.5));
    }