Modifying hover in Tailwindcss - css

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?

update: There is now a better way. See this answer by Javier Gonzalez
original:
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'

Using arbitrary variants
<button
type="button"
class="
[#media(hover:hover)]:opacity-0
[#media(hover:hover){&:hover}]:opacity-100
">
<!-- ... -->
</button>

Related

How to change specific elements style in storybook?

In my case I just want to change the default default color, take as example the default home section:
We recommend building UIs with a [**component-driven**](https://componentdriven.org)
That leads to:
I'd like to change that blue to, say, red.
I saw that the a class has the following themes:
class="sbdocs sbdocs-a css-19nbuh3"
So, I created a .storybook/manager-head.html and inside I wrote:
<style>
.sbdocs-a {
color: red;
}
But I see no changes! What am I doing wrong?
You can do this two ways but all in .storybook/preview.js.
Altering the docs theme:
export const parameters = {
...
docs: {
theme: {
colorSecondary: 'red',
},
},
...
};
This have the side effect to cause other unwanted components to change their color, as this color is not used only for links.
Provide your own <a> component to docs [best solution]:
export const parameters = {
...
docs: {
components: {
a: ({children, ...args}) => <a style={{color: 'red'}} {...args}>{children}</a>
},
},
...
};
This is the best way i found to style docs components.
also token name used for a can be found in storybook sources
See theming docs page for a full theme example.

How to acheive the font-variant-[caps,east-asian,ligatures] in Tailwind

Tried to use the JIT feature by adding this class font-[variant] without any effect.
I know that I can use the #apply directive and add the normal CSS, but I wanted to be sure that there is no Tailwind way to do it.
Any help is appreciated
Tailwind way will be to write custom plugin for every font-variant property. This example will add support for font-varaint-ligatures.
The way you tried font-variant-[variant] will not work because ligatures, east-easian, etc are part of a property, not a value
NOTE: unfortunatelly example bellow DOES NOT support JIT feature as a lack of information about support for adding custom JIT utilities (at least for now)
const plugin = require('tailwindcss/plugin');
module.exports = {
// ...config
plugins: [
plugin(
function ({ addUtilities, e }) {
// this class define how would you call it for ex 'variant-ligatures-[value]'
const yourClass = 'variant-ligatures';
// key - Tailwind 'caller', value - actual CSS property value
const values = {
'normal': 'normal',
'none': 'none',
'common': 'common-ligatures',
'no-common': 'no-common-ligatures',
'discretionary': 'discretionary-ligatures',
'no-discretionary': 'no-discretionary-ligatures',
'historical': 'historical-ligatures',
'no-historical': 'no-historical-ligatures',
'contextual': 'contextual',
'no-contextual': 'no-contextual',
'inherit': 'inherit',
'initial': 'initial',
'unset': 'unset',
};
// add support for responsive variants so you can use it like sm:variant-ligature-normal
const variants = ['responsive'];
addUtilities(
[
Object.entries(values).map(([key, value]) => {
return {
[`.${e(`${yourClass}-${key}`)}`]: {
'font-variant-ligatures': value, // CSS
},
}
}),
],
{ variants }
);
}
)
],
};
in this case variant-ligatures-historical will be rendered as
.variant-ligatures-historical {
font-variant-ligatures: historical-ligatures;
}
and sm:variant-ligatures-historical as
#media (min-width: 640px) {
.sm\:variant-ligatures-historical {
font-variant-ligatures: historical-ligatures;
}
}

JIT tailwindcss using variable in bg-[] not rendering color

when passing my color as props like this <List text="something" color="#84AB86" /> and using in the code className={'bg-[${color}] '} it does not render properly.
when looking at chrome dev tools color are added correctly like this bg-[#84AB86]
while putting the color manually without taking it from props, it does work correctly
after more testing it seems not possible either to do it like this
const color = "#84CC79"
className={`bg-[${color}]`}
any idea why
To use dynamic classes with JIT tailwind you either need to use safelist config key or create stub file where you list all your dynamic classes that you will use.
Config example:
module.exports = {
content: [
'./pages/**/*.{html,js}',
'./components/**/*.{html,js}',
],
safelist: [
'bg-red-500',
'text-3xl',
'lg:text-4xl',
]
// ...
}
Or make safelist.txt in your src folder, then add classes there just like so:
bg-[#84AB86]
bg-[#fffeee]
// etc..
And don't forget to include this safelist.txt file to your config content so tailwind could watch it.
Explanation from tailwind docs
If you are not using JIT, then you can use safelist option for PurgeCSS:
// tailwind.config.js
module.exports = {
purge: {
// Configure as you need
content: ['./src/**/*.html'],
// These options are passed through directly to PurgeCSS
options: {
// List your classes here, or you can even use RegExp
safelist: ['bg-red-500', 'px-4', /^text-/],
blocklist: [/^debug-/],
keyframes: true,
fontFace: true,
},
},
// ...
}
From the Tailwindcss documentation
Dynamic values Note that you still need to write purgeable HTML when
using arbitrary values, and your classes need to exist as complete
strings for Tailwind to detect them correctly.
Don't use string concatenation to create class names --> <div className={mt-[${size === 'lg' ? '22px' : '17px' }]}></div>
Do dynamically select a complete class name --> <div className={ size === 'lg' ? 'mt-[22px]' : 'mt-[17px]' }></div>
Tailwind doesn’t include any sort of client-side runtime, so class
names need to be statically extractable at build-time, and can’t
depend on any sort of arbitrary dynamic values that change on the
client. Use inline styles for these situations, or combine Tailwind
with a CSS-in-JS library like Emotion if it makes sense for your
project.
As mentioned above tailwind engine In order to render a custom class dynamicaly:
Does not like:
className={`bg-[${custom-color}]-100`}
It expects:
const customBgColorLight = 'bg-custom-color-100';
className={`${customBgColorLight} .....`}
For this to work properly you have to include the name of the class in the safelist:[] in your tailwind.config.js.
For tailwind v.3
/** #type {import('tailwindcss').Config} */
module.exports = {
content: ['./src/**/*.{js,jsx,ts,tsx}'],
safelist: [
'bg-custom-color-500', // your-custom-css-class
'text-custom-color-500',
'border-custom-color-500',
..... // other classes
'hover:bg-custom-color-500', // *** also include it with the selector if needed ***
.... // other classes
],
theme: {
extend: {
colors: {
'custom-color': { // you have to use quotes if key is not in camelCase format
100: '#d6d6d6',
500: '#5E8EA2',
..... //other variants
},
...... // other colors
So you can use it:
// if you want store the values to an object
const yourClassObj = {
customBgColor: 'bg-custom-color-500',
customBrdColor: 'border-custom-color-500',
customTxtColor: 'text-custom-color-500',
};
const { customBgColor, customBrdColor, customTxtColor } = yourClassObj;
<YourComponent
className={`mb-2 font-semibold py-2 px-4 rounded-lg
${ conditionGoesHere ? `${customBgColor} text-white cursor-default`
: `${customTxtColor} border ${customBrdColor}
bg-transparent hover:border-transparent
hover:${customBgColor} hover:text-white`
}`}
/>
An easy solution is to use the built in style property.
For example in React:
Dont Use:
className={`bg-[${color}]`}
Use Instead:
style={{
backgroundColor: color,
}}

Can you remove dashes from margin and padding classes in tailwind?

While using tailwind, is it possible to remove the dashes from margins and padding selectors?
For example:
.mb-1 would be .mb1
.-mx-1 would be .mxn1
I personally think this looks cleaner and wanted to know if it was possible.
It is possible through plugins, but requires a lot of extra work. Pulling from these two (one, two) github threads, here is an example of a plugin that removes the dash from the mb-# class, ie: .mb-1 will become .mb1:
import _ from 'lodash'
export default function(variants) {
return function ({ addUtilities, config }) {
const utilities = _.map(config('margin'), (value, modifier) => {
return defineClass(`mb${modifier}`, {
'margin-bottom': `${value}`,
})
})
addUtilities(utilities, variants)
}
}
Essentially the plugin is creating its own custom classes for the margin bottom class. It would take a lot of work to do this for each module but, again, it is possible. ps: the above plugin requires you to disable the default tailwind margin in your tailwind.config.js file.
module:
modules: {
// ...
- margin: [...],
+ margin: false,
// ...
}

Override components like MuiTab that use media queries

I'm trying to provide CSS overrides for MuiTab to increase the font-size.
Using the documentation about CSS overrides on material-ui I've managed to increase font size for most elements, however I got stuck at elements that use media queries as they produce more specific CSS rules than the ones I provide with my overrides.
theme.ts :
import { createMuiTheme } from '#material-ui/core';
const fontSizeStyle = {
fontSize: '1rem',
};
const fontFamilyStyle = {
fontFamily: '"Ubuntu", sans-serif'
};
const theme = createMuiTheme({
overrides: {
MuiTab: {
root: {
...fontFamilyStyle,
...fontSizeStyle,
},
label: fontSizeStyle,
},
}
});
export default theme;
This produces following css rules applied to a MuiTab:
The rule is generated by the following file:
https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/Tab/Tab.js
[theme.breakpoints.up('md')]: {
fontSize: theme.typography.pxToRem(13),
},
Does anyone have an example how to override this media query using createMuiTheme function? I don't have the breakpoints, so perhaps I need to specify breakpoints as well to be able to use them in my overrides
Kind regards
I solved it by specifying it in the following way:
MuiTab: {
root: {
minWidth: 0,
'#media (min-width: 0px)': {
minWidth: 0
}
}
}
Specify it as follows
let theme = createMuiTheme({});
theme = {
...theme,
overrides: {
MuiTab: {
root: {
[theme.breakpoints.up("xs")]: {
minHeight: 10
}
}
}
}
}
export default theme;
theme.breakpoints exposes four helper methods to create CSS media queries:
theme.breakpoints.up(key)
theme.breakpoints.down(key)
theme.breakpoints.only(key)
theme.breakpoints.between(start, end)
Where each key is a breakpoint and matches with a fixed screen width.
Allowed key values are xs|sm|md|lg|xl
See material-ui docs for more info
I also faced the same issue. I read the docs about Breakpoints and find a way for this situation but I find it kinda ugly as I have to apply the overridden styles in each Tab using classes property.
Note: I don't know the solution for this problem using createMuiTheme function
Apply the style to the breakpoints style. In this case,
const styles = theme => ({
mediaFont:{
[theme.breakpoints.up('md')]: {
fontSize:fontSizeStyle.fontSize,
},
},
});
Apply the above style to TabLabel
<Tab label="Item One" classes={{label:classes.mediaFont}} />
CSS has a mechanism for forcing a less specific rule to override a more specific one: !important.
const fontSizeStyle = {
fontSize: '1rem !important',
};

Resources