Modifying hover in Tailwindcss

Viewed 8779

I've noticed that :hover in Tailwindcss uses the defaults hover selector which causes 'stuck' hover states on mobile. Is there a way to modify the :hover function to do a @media(hover:hover) instead?

5 Answers

By far the simplest way is to add your own @media rule to the @responsive-class of rules in tailwind. How you can do that is described in the official tailwind documentation under the topic of custom media queries.

Simply add this to your config:

// tailwind.config.js
module.exports = {
    theme: {
        extend: {
          screens: {
            'hover-hover': {'raw': '(hover: hover)'},
      }
    }
  }
}

This translates to @media (hover: hover) { ... } in css. And voila, you could use hover-hover:text-red to display red text only for devices that have hover ability.

To make your own, leave 'raw' as is and change the other two attributes to whatever media query you want. The first attribute hover-hover is what you use in tailwind. The second (hover: hover) is what your actual css @media query looks like. E.g.: hover: none or pointer: coarse.

Now, go ahead and use hover-hover:hover:text-red to modify your hover states.

Might be a bit late but the Tailwind team is already addressing this issue in Tailwind version 3 using a feature flag: https://github.com/tailwindlabs/tailwindcss/pull/8394

Once a new version is published with these changes Starting on tailwindcss v3.1.0, you could include a feature flag in your configuration to look like:

// tailwind.config.js
module.exports = {
  future: {
    hoverOnlyWhenSupported: true,
  },
  // ...
}

Yes, just generate the hover variant using a plugin that, besides adding the :hover pseudo-selector, also wraps all of the rules inside an @media(hover:hover) rule:

// tailwind.config.js

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

const hoverPlugin = plugin(function({ addVariant, e, postcss }) {
    addVariant('hover', ({ container, separator }) => {
        const hoverRule = postcss.atRule({ name: 'media', params: '(hover: hover)' });
        hoverRule.append(container.nodes);
        container.append(hoverRule);
        hoverRule.walkRules(rule => {
            rule.selector = `.${e(`hover${separator}${rule.selector.slice(1)}`)}:hover`
        });
    });
});

module.exports = {
  plugins: [ hoverPlugin ],
}

The responsive attributes like sm: md: lg: will do those media query job for you. Refer example in the docs. If you dont want to use hover state in mobile device. specify with eg:- sm:hover:no-underline

You can easily create your own hover like below:

// styles.css

@variants hover {
  .banana {
    color: yellow;
  }
}

Then use it like class='hover:banana'

Related