Pseudo-Class Variants

Using utilities to style elements on hover, focus, and more.

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.

One
Two
Three
<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'],
  }
}

Tailwind UI is now in early access!