tailwindcss: Import does not work like documented

I’m trying to include a component. In the comments of the “bootstrap file” @import is used. This is not a funcionality provided by tailwind or is it?

I expect that I have to add postcss-import to my workflow. Am I wrong or are the docs wrong here?

If i import a file like dokumented i get an error.

/**
 * This injects Tailwind's base styles, which is a combination of
 * Normalize.css and some additional base styles.
 *
 * You can see the styles here:
 * https://github.com/tailwindcss/tailwindcss/blob/master/css/preflight.css
 */
@tailwind preflight;

/**
 * Here you would import any custom component classes; stuff that you'd
 * want loaded *before* the utilities so that the utilities can still
 * override them.
 * 
 * @import "my-components/foo";
 * @import "my-components/bar";
 */

@import "my-components/bar"; /*I added this one*/

/**
 * This injects all of Tailwind's utility classes, generated based on your
 * config file.
 */
@tailwind utilities;

And here the error:

@import must precede all other statements (besides @charset)

What am I doing wrong?

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 23
  • Comments: 24 (7 by maintainers)

Commits related to this issue

Most upvoted comments

Some people reading this far might find this summary useful. I solved this by switching the following lines in my main CSS file from:

@tailwind preflight;
@tailwind components;
@tailwind utilities;

to:

@import "tailwindcss/preflight";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

and ensuring postcss-import came before tailwind in my postcss config:

require('postcss-import'),
require('tailwindcss')('./src/css/tailwind.js'),

Thanks to the points made by @dotnetCarpenter and @adamwathan.

Since tailwind calls are not imports, it errors. As we’ve talked about in this thread, the solution is to wrap all of your code in separate files. Again, it’s not a Tailwind-specific issue; that’s how that plugin works.

thats all true.

Mmmh, maybe we could add some example configurations to https://tailwindcss.com/docs/installation#3-use-tailwind-in-your-css and not only the one example.

  • PostCSS only
  • SASS + Tailwind + PostCSS
  • LESS + Tailwind
  • SASS + Tailwind
  • LESS + Tailwind + PostCSS

This should not be a problem in maintenance because this one file most likely won’t change at all.

Some people reading this far might find this summary useful. I solved this by switching the following lines in my main CSS file from:

@tailwind preflight;
@tailwind components;
@tailwind utilities;

to:

@import "tailwindcss/preflight";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

and ensuring postcss-import came before tailwind in my postcss config:

require('postcss-import'),
require('tailwindcss')('./src/css/tailwind.js'),

Thanks to the points made by @dotnetCarpenter and @adamwathan.

Some people reading this far might find this summary useful. I solved this by switching the following lines in my main CSS file from:

@tailwind preflight;
@tailwind components;
@tailwind utilities;

to:

@import "tailwindcss/preflight";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

and ensuring postcss-import came before tailwind in my postcss config:

require('postcss-import'),
require('tailwindcss')('./src/css/tailwind.js'),

Thanks to the points made by @dotnetCarpenter and @adamwathan.

Thank you! thank you! you saved me many hours of work, I could not find a solution that worked for me! Now I just need to work with postcss-font-magician and it would be great!!

tailwind + webpack + postcss-import

Whether I missed this or not, one thing in addition to @harrygreen’s suggestion is this: @apply and @import in the same root css file will break things.

My webpack.config.js loads styles.css

const ExtractTextPlugin = require('extract-text-webpack-plugin')

const path = require('path')

module.exports = {
  entry: './index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'styles.css',
  },
  module: {
    rules: [{
      test: /\.css$/,
      exclude: /node_modules/,
      use: ExtractTextPlugin.extract({
        fallback: 'style-loader',
        use: [{
            loader: 'css-loader',
            options: {
              importLoaders: 1
            }
          },
          'postcss-loader'
        ]
      })
    }]
  },
  plugins: [
    new ExtractTextPlugin('styles.css')
  ]
}

This top-level styles.css only at-imports things:

/** Tailwind */
@import "tailwindcss/preflight";
@import "tailwindcss/components";

/** My components. */
@import "./alerts.css";

/* This would fail ---
.something {
   @apply .m-2
}
*/

/** Tailwind again */
@import "tailwindcss/utilities";

My alerts.css component:

.alert {
    @apply .m-2 .px-4 .py-3 .rounded
}
/* etc */

@psren Totally, we actually plan to add a separate page for each that documents any of the preprocessor-specific gotchas, like how you can’t nest @screen with Less, how you have to disable processCssUrls using Sass with Laravel Mix, or how you have to wrap Tailwind features with @css {} in Stylus.

Maybe just linking to some quick gists for each one from the docs would be a good interim solution though.

@rhyswat You’re misunderstanding the problem in your example — it’s not that using @apply in the same file as @import breaks things, it’s that you cannot have any non-import statements before any import statements.

In your example the reason adding the rule with @apply breaks things is because now you have a non-import statement preceding an import statement.

postcss-import will refuse to process this file for example:

.foo { color: blue }

@import "tailwindcss/utilities";

…because .foo { ... } comes before @import "tailwindcss/utilities" which is not allowed as per the spec:

The @import CSS at-rule is used to import style rules from other style sheets. These rules must precede all other types of rules, except @charset rules.

This will totally work:

/** Tailwind */
@import "tailwindcss/preflight";
@import "tailwindcss/components";

/** My components. */
@import "./alerts.css";

/** Tailwind again */
@import "tailwindcss/utilities";

.something {
   @apply .m-2
}

But you might not want your CSS in that order. In that case, the correct solution is for this file to only contain import statements and any non-import rules to other files that can be imported, so that you are following the spec while still having control over your CSS order.

So again it has nothing to do with @apply, postcss-import just doesn’t allow you to have any CSS come before any import statements.

Thanks for clarifying. I think the following is very confusing:

/* Or if using a preprocessor:
*
* @import "components/buttons";
* @import "components/forms";
*/

Since PostCSS is a transpiler, which makes it a preprocessor in my book, not writing how to use tailwind with PostCSS import transformations is very confusing. Can we agree to a different wording?

@dotnetCarpenter You need to run postcss-import before Tailwind and make sure any @tailwind calls are moved out to their own files to satisfy that error you pasted:

@import must precede all other statements (besides @charset)

The problem is @tailwind is coming before an @import which is invalid according to the CSS spec, and postcss-import is strict about that. You’d get the same error even if you had a file like this:

.foo {
  color: blue;
}

@import "icons.css";

So it’s not really a Tailwind issue specifically, just that when using postcss-import you can’t have any additional code before any @import statements.

So the solution like you noticed is to make your main CSS file only import statements, so you’re free to order them as you like. This means wrapping all other code (including @tailwind statements) in separate files.

@reinink the trick mentioned by @SmashBrando works. I already use postcss-import, but this plugin produced this warning.

Now I import the @tailwind preflight; from an other file. My main.css looks like that:

@import "_reset";
@import "_breadcrumb";
@import "_utilities";

and i moved the @tailwind … calls to _reset/_utilities.

This is not optimal, maybe we can document this behaviour on https://tailwindcss.com/docs/installation in a extra using with postcss-import seciton or smth. like that?

Or maybe you a better way and want to share your config?

@reinink I’m also trying to get this to work using the postcss-import plugin and am getting the same error. @import must precede all other statements (besides @charset)

Would you mind sharing a sample gulp config?

Here is mine.

var gulp = require('gulp');
gulp.task('css', function () {
  var postcss = require("gulp-postcss");
  var atimport = require('postcss-import');
  var tailwindcss = require("tailwindcss");
  return gulp.src('styles/style.css')
    .pipe(postcss([
      atimport(),
      tailwindcss('./styles/config.js'),
      require('autoprefixer'),
    ]))
    .pipe(gulp.dest(''));
});

Edit: after a bit more digging, I can get this to work by creating a style.css entry point that imports my base tailwinds css and then any other files.

If you’re using Tailwind with plain old CSS (which you can totally do), then you’ll need to use a PostCSS library that supports inline imports. I use postcss-import. You may also want to look at using cssnext, which I believe includes this by default.

Let me know if that doesn’t solve your issues!

@burmashave that’s because it only mentions how to install tailwindcss itself on that page. It doesn’t make any assumptions on what other plugins you might or might not use.

From the postcss-import docs:

This plugin should probably be used as the first plugin of your list. This way, other plugins will work on the AST as if there were only a single file to process, and will probably work as you can expect.

Might be helpful to add a note about plugin order being important and affecting the generated CSS. Pretty sure a PR that mentions it would be welcome (without being too specific and refering to just one plugin).

Keep in mind that some postcss plugins, like postcss-import, must come before tailwind to make it work.

@adamwathan I think the docs miss this tiny piece from @harrygreen 's answer above:

…and ensuring postcss-import came before tailwind in my postcss config

I was pulling my hair out till I found this 🙂

I have the same problem, I am trying this in a Laravel project but I can’t do it using scss.

@adamwathan Can you share a sample vue-cli project where we can use the @apply directive in imported stylesheets? I wasted a day trying every suggested solution in here.

Already mentioned in this page:

Then add it as the very first plugin in your PostCSS configuration

True, but the examples in the installation document do not make this clear.