tailwindcss: preflight button reset in v3 inconsistent with v2

What version of Tailwind CSS are you using?

For example: v3.0.6

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

postcss: 8.3.11 webpack: 5.65.0

What version of Node.js are you using?

v14.16.1

What browser are you using?

Chrome

What operating system are you using?

macOS

Reproduction URL

https://play.tailwindcss.com/AJDoBTeOhx

Describe your issue

https://github.com/tailwindlabs/tailwindcss/pull/5358 removes the dependency on modern-normalize, and then inlines and consolidates it with preflight.

During this consolidation it appears as:

button {
  background-color: transparent;
  background-image: none;
}

was merged with:

button,
[type='button'],
[type='reset'],
[type='submit'] {
  -webkit-appearance: button;
}

Resulting in

/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Remove default button styles.
*/
button,
[type='button'],
[type='reset'],
[type='submit'] {
  -webkit-appearance: button; /* 1 */
  background-color: transparent; /* 2 */
  background-image: none; /* 2 */
}

Since [type='button'], [type='reset'], [type='submit'] have high specificity simple background-color and background-image styles included before tailwind are being overridden. This did not occur in v2 when the rules were separate. (I recognize this is not best practices but I am working in a legacy app.)

I would be happy to open a PR that breaks apart the rules restoring v2 behavior (if that is desired):

/*
Remove default button styles.
*/

button {
  background-color: transparent;
  background-image: none;
}

/*
Correct the inability to style clickable types in iOS and Safari.
*/

button,
[type='button'],
[type='reset'],
[type='submit'] {
  -webkit-appearance: button;
}

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 30
  • Comments: 34 (4 by maintainers)

Commits related to this issue

Most upvoted comments

FWIW I worked around this by disabling preflight: https://tailwindcss.com/docs/preflight#disabling-preflight

module.exports = {
  corePlugins: {
    // due to https://github.com/tailwindlabs/tailwindcss/issues/6602 - buttons disappear
    preflight: false,
  },
  ...
}

You could then potentially add a variant of preflight manually, but it is unfortunate.

I ended up including a copy of preflight in my repo then commented out the reset of background image and color.

Update 2023: I actually end up using a script to include preflight separately so I can ensure it is injected before my css-in-js (controlled via a jss insertion point). I add this to my package.json scripts:

"build:preflight": "tailwindcss -i ./node_modules/tailwindcss/lib/css/preflight.css -o public/preflight.css",

Then something like this in my index.html

    <!-- disable auto-inclusion of this with tailwind so we can have it 
    inserted manually before our css-in-js -->
    <link rel="stylesheet" href="/preflight.css" id="preflightcss" />
    <!-- use this DOM node as the insertion point for our css-in-js -->
    <noscript id="jss-insertion-point"></noscript>

we use another ui libary and it also auto insert css style in head, tailwind always gen css in the last position, so still have conflict with it

I have the same issue with Mantine.

it happen with @mui components also…

We’re having similar issues with Preflight reset in v3.0.10 as well, where buttons always get background-color: transparent in a project migrating from a css-in-js ui library

Hey! This is intentional to correct an inconsistency, it was unintentional that <button> and <input type="submit"> had originally had different styles.

If you have any custom CSS adding styles to these elements, you should make sure it is loaded after the preflight reset — that was always the intended place for people to add their own base styles.

Problem: preflight reset was overriding button and input styles

Solution: now solved, see below.

Thanks to the creators and maintainers of Tailwind! This amazing CSS tool has abstracted away all of the things I hated about CSS (and loved about lightning fast prototyping with inline styles).

First off, I am a non-developer. Just playing with Rails and Tailwind.

I spent parts of 2-3 days troubleshooting why the “bg-sky-800” class was not working in my Tailwind install on Rails 7 for styling an input “submit”. Turns out I had a “font-regular” class selector in my code which Tailwind indicated is a “class that does not exist”.

This was breaking a whole bunch of things including the ability to use some class selectors (but not all). To try to style the input “submit” I had to resort to the method others mentioned of changing the TW reset and fiddling with the button and input reset selectors. That monkey patch sort of worked, but I could tell some things were still broken.

Finding the “font-regular” error seemed to fix everything which was unexpected. Just thought I woudl share my experience in case it helps everyone.

I would recommend using: bin/rails tailwindcss:watch to have a process running that automatically rebuilds Tailwind when changes are made in your app. That way you can spot if anything is breaking the build.

Thanks again to Adam and the team, I won’t be going back to regular CSS ever again.

  • Dan H

@hectorperez What you’ve outlined in your comment definitely should work, as demonstrated in this Tailwind Play:

https://play.tailwindcss.com/ANnGuGzLLE?file=css

That approach is definitely the correct way to override a style from Preflight, demo’d again here for anyone reading:

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
  button,.button,input[type='button'],input[type='reset'],input[type='submit'] {
    @apply bg-blue-600;
  }
}

what was this closed? if is still an issue?

This is causing issues when mixing Tailwind with Bootstrap, despite using a prefix for Tailwind

This block


/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Remove default button styles.
*/

button,
[type='button'],
[type='reset'],
[type='submit'] {
  -webkit-appearance: button; /* 1 */
  background-color: transparent; /* 2 */
  background-image: none; /* 2 */
}

Is causing Bootstrap buttons to fade-out as soon as they appear.

How to disable this behaviour? This is new with 3.0…

Can this please be reopened?

my solution is :

  1. add preflight to tailwind config
module.exports = {
  corePlugins: {
    preflight: false
  }
}
  1. find node_modules/tailwindcss/src/css/preflight.css, copy this file to your own reset.css
  2. find below code, and commit the background-color
button,
[type='button'],
[type='reset'],
[type='submit'] {
	-webkit-appearance: button; /* 1 */
	// just commit this line
	background-color: transparent; /* 2 */
	background-image: none; /* 2 */
}
  1. delete some error code in it, and import your own reset.css to your project.

I have the same problem with Mantine React library. To bypass the problem, I have added the cdn tailwind link (2.2.19) in the header of public/index.html.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My App</title>
    <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
</head>
<body>
    <div id="root"></div>
    <script type="module" src="../src/index.tsx"></script>
</body>
</html>

Surprisingly, everything works fine for me when I use cra (create-react-app), but when I use vite, buttons are transparent by default. It’s super annoying. As said above, setting preflight to false doesn’t do the trick as it disables too many styles. The following styles are applied.

button, [type='button'], [type='reset'], [type='submit'] {
    -webkit-appearance: button;
    background-color: transparent;
    background-image: none;
}

Hello, I just encountered this issue and the solution that i found is usindgthe important modifier, more on this here, this way we can get away with this line of code html <div class="!bg-black text-white">Button</div>.

This work to me, on my case i’m using hover classes on buttons and solve the issue with this

!bg-blue-700 hover:!bg-blue-800

Pasting my response from the linked PR in case it’s helpful here:


In CSS, declaration order is important, so you always want base styles early in the stylesheet, and more specific styles later in the stylesheet.

If you are combining Tailwind with some other CSS (custom or another library like Bootstrap or Material UI), it’s important that you combine all of those styles in a deliberate order to avoid override issues.

You definitely don’t want your CSS to look something like this:

@import "./bootstrap.css";
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

…because now styles in @tailwind base are going to override styles in Bootstrap.

You instead want to structure your CSS so all of your base styles are first, followed by all of your component styles, followed by all of your utility styles. This means you can’t really group all of Bootstrap together and all of Tailwind together and load them in sequence without issues, and is why Tailwind separates those three layers so you can insert other CSS in between them in the right order.

Ideally you want to structure things more like:

@import "bootstrap-base-styles";
@import "tailwindcss/base";

@import "bootstrap-component-styles";
@import "tailwindcss/components";

@import "bootstrap-utility-styles";
@import "tailwindcss/utilities";

But how you actually achieve this is up to you — Tailwind tries hard to give you as much flexibility in how you do this on our side but of course we can’t control how other libraries bundle their CSS or what flexibility they offer in splitting up the different types of styles so you can put things in a sensible order.

If you have no control over the ordering and can’t prevent conflicts between Preflight and your other styles, the recommendation is to disable Preflight:

// tailwind.config.js
module.exports = {
  corePlugins: {
    preflight: false
  }
}

I totally understand and empathize with this being a bit of an annoying problem, but I worry that merging this PR is simply a band-aid for that one specific case. Every rule in Preflight has the same potential to override styles in other libraries if you don’t solve the core ordering problem, for example if you are using a make-believe library like AcmeCSS that includes this rule:

hr {
  border-bottom-width: 2px;
}

…then this rule from Preflight is going to break that style if Preflight is loaded after AcmeCSS:

hr {
  height: 0; /* 1 */
  color: inherit; /* 2 */
  border-top-width: 1px; /* 3 */
}

So again I’m sorry that this is an issue that people are facing but the right solution isn’t to change any of the styles in Preflight, it’s to merge all of your styles together in the right order such that the styles you want to override other styles come later in the stylesheet, and Tailwind already splits our styles into three separate layers to make sure we give you every opportunity to do that.

Thanks regardless for the PR, hope this explanation is helpful.

I am using Uppy image

Even though the button has classes uppy-u-reset uppy-c-btn uppy-StatusBar-actionBtn uppy-StatusBar-actionBtn--retry Tailwind is selected over the class uppy-StatusBar-actionBtn--retry.

It is very fortunate that the tailwind selector is so strong, since other libraries depend on the default css behavior of a HTML button. According to https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity it may only be overwritten by using id-selector.

Just styling a button in tailwind now requires !important flag like !bg-red-500 hover:!bg-red-600. Yikes!

For using a component lib like this, there is no easy work around. Setting preflight to false disables too much styling which you would rely on in a tailwind project.

Overwriting it with the “legacy” style is also not possible since (a) it is not legacy and (b) you need to reimport all style of the respective component library.

@adamwathan maybe you can consider moving back to the behavior of Tailwind 2. Is it so important to quasi match the styles of input and button?

@konsalex preflight defaults are handy for me so for now I’ll do what you propose: disable preflight & add the source without background-color: transparent.

Thanks!

I solve this the same way with @pbeshai, it is unfortunate, hoped for a smooth-less upgrade from v2

I am having this issue with the button background color being transparent in nextjs when adding tailwind @apply directives to the globals.css file. This is maddening and no offense to the clever and hard working solutionists but these solutions look ugly to me! Can we get a fix?

Hello, I just encountered this issue and the solution that i found is usindgthe important modifier, more on this here, this way we can get away with this line of code html <div class="!bg-black text-white">Button</div>.

In my case this happened because of I am adding

import ‘tailwindcss/base.css’; in the index.js file

in my reactjs project and also add

@tailwind base; @tailwind components; @tailwind utilities;

in index.css

when I remove this line import ‘tailwindcss/base.css’; from index.js

it works.

@konsal

@hectorperez For me to work I disabled the preflight. But if you still want the preflight defaults, as some are helpful, this is the source, include this by hand into your source css file, and remove the button reset 🚀

Great suggestion! Only now after manually adding the css files the component styling stutters after hard refreshing the page (I’m using next). Any clue why?

@josephlavin Here’s a demo that demonstrates the recommended solution to your original reproduction:

https://play.tailwindcss.com/mKQiNQm5kL?file=css

You need to make sure any legacy styles that should override Tailwind’s base styles come after @tailwind base:

@tailwind base;

.legacy-styles{
  background-color: red;
}

@tailwind components;
@tailwind utilities;

@hectorperez For me to work I disabled the preflight. But if you still want the preflight defaults, as some are helpful, this is the source, include this by hand into your source css file, and remove the button reset 🚀