Pseudo-Class Variants
Overview
Similar to how Tailwind handles responsive design, styling elements on hover, focus, and more can be accomplished by prefixing utilities with the appropriate pseudo-class.
<form>
<input className="bg-gray-200 hover:bg-white hover:border-gray-300 focus:outline-none focus:bg-white focus:shadow-outline focus:border-gray-300 ..."/>
<button className="bg-teal-500 hover:bg-teal-600 focus:outline-none focus:shadow-outline ...">
Sign Up
</button>
</form>
Not all pseudo-class variants are enabled for all utilities by default due to file-size considerations, but we've tried our best to enable the most commonly used combinations out of the box.
For a complete list of which variants are enabled by default, see the reference table at the end of this page.
Tailwind includes first-class support for styling elements on hover, focus, active, disabled, visited, first-child, last-child, odd-child, even-child, group-hover, group-focus, and focus-within.
If you need to target a pseudo-class that Tailwind doesn't support, you can extend the supported variants by writing a variant plugin.
Hover
Add the hover:
prefix to only apply a utility on hover.
`}
You can control whether hover
variants are enabled for a utility in the variants
section of your tailwind.config.js
file:
// tailwind.config.js
module.exports = {
// ...
variants: {
backgroundColor: ['responsive', 'hover', 'focus'],
},
}
Focus
Add the focus:
prefix to only apply a utility on focus.
`}
You can control whether focus
variants are enabled for a utility in the variants
section of your tailwind.config.js
file:
// tailwind.config.js
module.exports = {
// ...
variants: {
backgroundColor: ['responsive', 'hover', 'focus'],
},
}
Active
Add the active:
prefix to only apply a utility when an element is active.
`}
You can control whether active
variants are enabled for a utility in the variants
section of your tailwind.config.js
file:
// tailwind.config.js
module.exports = {
// ...
variants: {
backgroundColor: ['responsive', 'hover', 'focus', 'active'],
},
}
Disabledv1.1.0+
Add the disabled:
prefix to only apply a utility when an element is disabled.
`}
You can control whether disabled
variants are enabled for a utility in the variants
section of your tailwind.config.js
file:
// tailwind.config.js
module.exports = {
// ...
variants: {
opacity: ['responsive', 'hover', 'focus', 'disabled'],
},
}
Visitedv1.1.0+
Add the visited:
prefix to only apply a utility when a link has been visited.
`}
You can control whether visited
variants are enabled for a utility in the variants
section of your tailwind.config.js
file:
// tailwind.config.js
module.exports = {
// ...
variants: {
textColor: ['responsive', 'hover', 'focus', 'visited'],
},
}
First-childv1.1.0+
Add the first:
prefix to only apply a utility when it is the first-child of its parent. This is mostly useful when elements are being generated in some kind of loop.
<div className="border rounded">
<div v-for="item in items" className="border-t first:border-t-0">
@ item @@
</div>
</div>
It's important to note that you should add any first:
utilities to the child element, not the parent element.
You can control whether first
variants are enabled for a utility in the variants
section of your tailwind.config.js
file:
// tailwind.config.js
module.exports = {
// ...
variants: {
borderWidth: ['responsive', 'first', 'hover', 'focus'],
},
}
Last-childv1.1.0+
Add the last:
prefix to only apply a utility when it is the last-child of its parent. This is mostly useful when elements are being generated in some kind of loop.
`}
It's important to note that you should add any last:
utilities to the child element, not the parent element.
You can control whether last
variants are enabled for a utility in the variants
section of your tailwind.config.js
file:
{`
// tailwind.config.js
module.exports = {
// ...
variants: {
borderWidth: ['responsive', 'last', 'hover', 'focus'],
},
}
`}
Odd-childv1.1.0+
Add the odd:
prefix to only apply a utility when it is an odd-child of its parent. This is mostly useful when elements are being generated in some kind of loop.
`}
It's important to note that you should add any odd:
utilities to the child element, not the parent element.
You can control whether odd
variants are enabled for a utility in the variants
section of your tailwind.config.js
file:
// tailwind.config.js
module.exports = {
// ...
variants: {
borderWidth: ['responsive', 'odd', 'hover', 'focus'],
},
}
Even-childv1.1.0+
Add the even:
prefix to only apply a utility when it is an even-child of its parent. This is mostly useful when elements are being generated in some kind of loop.
`}
It's important to note that you should add any even:
utilities to the child element, not the parent element.
You can control whether even
variants are enabled for a utility in the variants
section of your tailwind.config.js
file:
// tailwind.config.js
module.exports = {
// ...
variants: {
borderWidth: ['responsive', 'even', 'hover', 'focus'],
},
}
Group-hover
If you need to style a child element when hovering over a specific parent element, add the .group
class to the parent element and add the group-hover:
prefix to the utility on the child element.
New Project
Create a new project from a variety of starting templates.
<div className="group bg-white hover:bg-blue-500 ...">
<p className="text-gray-900 group-hover:text-white ...">New Project</p>
<p className="text-gray-700 group-hover:text-white ...">Create a new project from a variety of starting templates.</p>
</div>
You can control whether group-hover
variants are enabled for a utility in the variants
section of your tailwind.config.js
file:
// tailwind.config.js
module.exports = {
// ...
variants: {
textColor: ['responsive', 'hover', 'focus', 'group-hover'],
},
}
Group-focusv1.3.0+
The group-focus
variant works just like group-hover
except for focus:
`}
You can control whether group-focus
variants are enabled for a utility in the variants
section of your tailwind.config.js
file:
// tailwind.config.js
module.exports = {
// ...
variants: {
textColor: ['responsive', 'hover', 'focus', 'group-focus'],
},
}
Focus-within
Note that focus-within is not supported in IE or Edge < 79.
Add the focus-within:
prefix to only apply a utility when a child element has focus.
<form className="border-b-2 border-gray-400 focus-within:border-teal-500 ...">
<input className="..." placeholder="Jane Doe" ... />
<button className="...">
Sign Up
</button>
</form>
You can control whether focus-within
variants are enabled for a utility in the variants
section of your tailwind.config.js
file:
// tailwind.config.js
module.exports = {
// ...
variants: {
borderColor: ['responsive', 'hover', 'focus', 'focus-within'],
},
}
Combining with responsive prefixes
Pseudo-class variants are also responsive, meaning you can do things like change an element's hover style at different breakpoints for example.
To apply a pseudo-class variant at a specific breakpoint, add the responsive prefix first, before the pseudo-class prefix:
all
sm
md
lg
xl
null
Generative variants for custom utilities
You can generate pseudo-class variants for your own custom utilities by wrapping them with the @@variants
directive in your CSS:
/* Input: */
@@variants group-hover, hover, focus {
.banana {
color: yellow;
}
}
/* Output: */
.banana {
color: yellow;
}
.group:hover .group-hover\:banana {
color: yellow;
}
.hover\:banana:hover {
color: yellow;
}
.focus\:banana:focus {
color: yellow;
}
For more information, see the @@variants directive documentation.
Creating custom variants
You can create your own variants for any pseudo-classes Tailwind doesn't include by default by writing a custom variant plugin.
For example, this simple plugin adds support for the disabled
pseudo-class variant:
// tailwind.config.js
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addVariant, e }) {
addVariant('disabled', ({ modifySelectors, separator }) => {
modifySelectors(({ className }) => {
return `.${e(`disabled${separator}${className}`)}:disabled`
})
})
})
]
}
Learn more about writing variant plugins in the variant plugin documentation.
Default variants reference
Due to file-size considerations, Tailwind does not include all variants for all utilities by default.
To configure which variants are enabled for your project, see the configuring variants documentation.
// Default configuration
module.exports = {
// ...
variants: {
accessibility: ['responsive', 'focus'],
alignContent: ['responsive'],
alignItems: ['responsive'],
alignSelf: ['responsive'],
appearance: ['responsive'],
backgroundAttachment: ['responsive'],
backgroundColor: ['responsive', 'hover', 'focus'],
backgroundOpacity: ['responsive', 'hover', 'focus'],
backgroundPosition: ['responsive'],
backgroundRepeat: ['responsive'],
backgroundSize: ['responsive'],
borderCollapse: ['responsive'],
borderColor: ['responsive', 'hover', 'focus'],
borderOpacity: ['responsive', 'hover', 'focus'],
borderRadius: ['responsive'],
borderStyle: ['responsive'],
borderWidth: ['responsive'],
boxShadow: ['responsive', 'hover', 'focus'],
boxSizing: ['responsive'],
clear: ['responsive'],
cursor: ['responsive'],
display: ['responsive'],
divideColor: ['responsive'],
divideOpacity: ['responsive'],
divideWidth: ['responsive'],
fill: ['responsive'],
flex: ['responsive'],
flexDirection: ['responsive'],
flexGrow: ['responsive'],
flexShrink: ['responsive'],
flexWrap: ['responsive'],
float: ['responsive'],
fontFamily: ['responsive'],
fontSize: ['responsive'],
fontSmoothing: ['responsive'],
fontStyle: ['responsive'],
fontWeight: ['responsive', 'hover', 'focus'],
gap: ['responsive'],
gridAutoFlow: ['responsive'],
gridColumn: ['responsive'],
gridColumnEnd: ['responsive'],
gridColumnStart: ['responsive'],
gridRow: ['responsive'],
gridRowEnd: ['responsive'],
gridRowStart: ['responsive'],
gridTemplateColumns: ['responsive'],
gridTemplateRows: ['responsive'],
height: ['responsive'],
inset: ['responsive'],
justifyContent: ['responsive'],
letterSpacing: ['responsive'],
lineHeight: ['responsive'],
listStylePosition: ['responsive'],
listStyleType: ['responsive'],
margin: ['responsive'],
maxHeight: ['responsive'],
maxWidth: ['responsive'],
minHeight: ['responsive'],
minWidth: ['responsive'],
objectFit: ['responsive'],
objectPosition: ['responsive'],
opacity: ['responsive', 'hover', 'focus'],
order: ['responsive'],
outline: ['responsive', 'focus'],
overflow: ['responsive'],
padding: ['responsive'],
placeholderColor: ['responsive', 'focus'],
placeholderOpacity: ['responsive', 'focus'],
pointerEvents: ['responsive'],
position: ['responsive'],
resize: ['responsive'],
rotate: ['responsive', 'hover', 'focus'],
scale: ['responsive', 'hover', 'focus'],
skew: ['responsive', 'hover', 'focus'],
space: ['responsive'],
stroke: ['responsive'],
strokeWidth: ['responsive'],
tableLayout: ['responsive'],
textAlign: ['responsive'],
textColor: ['responsive', 'hover', 'focus'],
textDecoration: ['responsive', 'hover', 'focus'],
textOpacity: ['responsive', 'hover', 'focus'],
textTransform: ['responsive'],
transform: ['responsive'],
transformOrigin: ['responsive'],
transitionDelay: ['responsive'],
transitionDuration: ['responsive'],
transitionProperty: ['responsive'],
transitionTimingFunction: ['responsive'],
translate: ['responsive', 'hover', 'focus'],
userSelect: ['responsive'],
verticalAlign: ['responsive'],
visibility: ['responsive'],
whitespace: ['responsive'],
width: ['responsive'],
wordBreak: ['responsive'],
zIndex: ['responsive'],
}
}