Tailwind CSS plugin to generate transition utilities

  • By Benoît Rouleau
  • Last update: Sep 5, 2022
  • Comments: 11

⛔️ DEPRECATED

Tailwind CSS 1.2 (released in February 2020) has utilities for transition property, duration, and timing function. It doesn’t have transition delay or will-change utilities (yet), nor does it have a way to define a default transition duration or timing function, but I feel like keeping this plugin around would be more confusing than helpful since it uses similar (or identical in some cases) class names as the core transition utilities. Feel free to fork it if you want, but I recommend migrating to Tailwind’s official solution and write custom utilities for transition-delay and will-change when needed.

Transitions Plugin for Tailwind CSS

Installation

npm install tailwindcss-transitions

Usage

// tailwind.config.js
module.exports = {
  theme: {
    transitionProperty: { // defaults to these values
      'none': 'none',
      'all': 'all',
      'default': ['background-color', 'border-color', 'color', 'fill', 'stroke', 'opacity', 'box-shadow', 'transform'],
      'colors': ['background-color', 'border-color', 'color', 'fill', 'stroke'],
      'bg': 'background-color',
      'border': 'border-color',
      'color': 'color',
      'opacity': 'opacity',
      'shadow': 'box-shadow',
      'transform': 'transform',
    },
    transitionDuration: { // defaults to these values
      'default': '250ms',
      '0': '0ms',
      '50': '50ms',
      '75': '75ms',
      '100': '100ms',
      '150': '150ms',
      '200': '200ms',
      '250': '250ms',
      '300': '300ms',
      '400': '400ms',
      '500': '500ms',
      '750': '750ms',
      '1000': '1000ms',
    },
    transitionTimingFunction: { // defaults to these values
      'default': 'ease',
      'linear': 'linear',
      'ease': 'ease',
      'ease-in': 'ease-in',
      'ease-out': 'ease-out',
      'ease-in-out': 'ease-in-out',
    },
    transitionDelay: { // defaults to these values
      'default': '0ms',
      '0': '0ms',
      '100': '100ms',
      '250': '250ms',
      '500': '500ms',
      '750': '750ms',
      '1000': '1000ms',
    },
    willChange: { // defaults to these values
      'auto': 'auto',
      'scroll': 'scroll-position',
      'contents': 'contents',
      'opacity': 'opacity',
      'transform': 'transform',
    },
  },
  variants: { // all the following default to ['responsive']
    transitionProperty: ['responsive'],
    transitionDuration: ['responsive'],
    transitionTimingFunction: ['responsive'],
    transitionDelay: ['responsive'],
    willChange: ['responsive'],
  },
  plugins: [
    require('tailwindcss-transitions')(),
  ],
};

The default configuration generates the following CSS:

/* base styles for the default transition duration, timing function, and delay (when they differ from the CSS defaults) */
*, *::before, *::after {
  --transition-duration: 250ms;
  /* when the default timing function is a value other than "ease": */
  --transition-timing-function: [default-timing-function];
  /* when the default delay is a value other than zero: */
  --transition-delay: [default-delay];
}

/* configurable with the "transitionProperty" theme object */
.transition-none {
  transition-property: none;
  transition-duration: 250ms;
  transition-duration: var(--transition-duration);
}
.transition-all {
  transition-property: all;
  transition-duration: 250ms;
  transition-duration: var(--transition-duration);
}
.transition {
  transition-property: background-color, border-color, color, fill, stroke, opacity, box-shadow, transform;
  transition-duration: 250ms;
  transition-duration: var(--transition-duration);
}
.transition-[property-key] {
  transition-property: [property-value];
  /* when the default duration is a value other than zero: */
  transition-duration: [default-duration];
  transition-duration: var(--transition-duration);
  /* when the default timing function is a value other than "ease": */
  transition-timing-function: [default-timing-function];
  transition-timing-function: var(--transition-timing-function);
  /* when the default delay is a value other than zero: */
  transition-delay: [default-delay];
  transition-delay: var(--transition-delay);
}

/* configurable with the "transitionDuration" theme object */
.transition-0 {
  --transition-duration: 0ms;
  transition-duration: 0ms;
  transition-duration: var(--transition-duration);
}
.transition-50 {
  --transition-duration: 50ms;
  transition-duration: 50ms;
  transition-duration: var(--transition-duration);
}
.transition-[duration-key] {
  transition-duration: [duration-value];
  /* when the default duration is a value other than zero: */
  --transition-duration: [duration-value];
  transition-duration: var(--transition-duration);
  /* when the default timing function is a value other than "ease": */
  transition-timing-function: [default-timing-function];
  transition-timing-function: var(--transition-timing-function);
  /* when the default delay is a value other than zero: */
  transition-delay: [default-delay];
  transition-delay: var(--transition-delay);
}

/* configurable with the "transitionTimingFunction" theme object */
.transition-linear {
  transition-timing-function: linear;
}
.transition-ease {
  transition-timing-function: ease;
}
.transition-[timing-function-key] {
  transition-timing-function: [timing-function-value];
  /* when the default timing function is a value other than "ease": */
  --transition-timing-function: [timing-function-value];
  transition-timing-function: var(--transition-timing-function);
}

/* configurable with the "transitionDelay" theme object */
.transition-delay-0 {
  transition-delay: 0ms;
}
.transition-delay-100 {
  transition-delay: 100ms;
}
.transition-delay-[key] {
  transition-delay: [value];
  /* when the default delay is a value other than zero: */
  --transition-delay: [value];
  transition-delay: var(--transition-delay);
}

/* configurable with the "willChange" theme object */
.will-change {
  will-change: contents;
}
.will-change-auto {
  will-change: auto;
}
.will-change-[key] {
  will-change: [value];
}

Which you can then use in your HTML like this:

Hover me for a lighter background ">
<button class="bg-gray-600 hover:bg-gray-500 transition-bg">
  Hover me for a lighter background
button>

<button class="bg-gray-200 hover:bg-gray-900 text-gray-900 hover:text-gray-200 transition-colors transition-500 transition-linear">
  Hover me to invert colors
button>

Note: The transitionProperty, transitionDuration, transitionTimingFunction, and transitionDelay theme objects accept a default key. For transitionProperty, it generates a simple transition class (instead of transition-default), but for the other three, default doesn’t generate any class; it is used to define a custom property on all elements and pseudo-elements (*, *::before, *::after) if the value differs from the CSS-defined default. These custom properties are then used to set actual properties on elements that have a transition-[property] or transition-[duration] class, so that you don’t have to define a duration, timing function, or delay every time.

Github

https://github.com/benface/tailwindcss-transitions

Comments(11)

  • 1

    Explore not resetting `transition-property` to `none`

    Right now, the base styles set transition-duration to the default duration and transition-property to none. As a result:

    • transition-all applies a transition with the default duration
    • transition-all transition-500 customizes the duration
    • transition-opacity customizes the property but applies the default duration
    • transition-opacity transition-500 customizes both the property and the duration
    • transition-500 alone doesn't do anything (the property is still set to none)

    However, this creates issues with 3rd party libraries that don't expect transition-property and transition-duration to be different from their CSS-defined defaults (all and 0s, respectively).

    It could be interesting to not have any base styles, unless the user customized the default transitionProperty (which would be all by default), the default transitionTimingFunction (ease by default), and/or the default transitionDelay (0s by default). So it would then work like this:

    • transition applies a transition with the default duration
    • transition-500 customizes the duration
    • transition transition-opacity customizes the property but applies the default duration
    • transition-500 transition-opacity customizes both the property and the duration
    • transition-opacity alone doesn't do anything (the duration is still set to 0s)

    This would obviously be a breaking change, and I'm not convinced it's better. Is it clear that transition sets the transition-duration property, so that if you want to customize the transitionable property, you need to add a transition-opacity class and not just append -opacity to the existing transition class? Curious to hear others' thoughts!

  • 2

    No Copyright Licence

    Hi,

    I found your project it completely solves my problems but to use it on the project that I'm working on I need to have a copyright licence, do you think it could be possible to add it to the project?

    You're under no obligation to choose a license. However, without a license, the default copyright laws apply, meaning that you retain all rights to your source code and no one may reproduce, distribute, or create derivative works from your work. If you're creating an open source project, we strongly encourage you to include an open source license. The Open Source Guide provides additional guidance on choosing the correct license for your project.

    https://help.github.com/en/articles/licensing-a-repository

    Thanks in advance, cheers

  • 3

    Allow for values to be defined as numbers but be output as ms

    When in Javascript I kind of expect numbers to be milliseconds in these situations. This makes that a reality.

    It would also make getting the durations for other purposes from the tailwind config a little smoother since most things want a number in JS (for setTimeout fallback type situations).

    I can totally be making this up, but we're not breaking anything here either.

  • 4

    Setting up PurgeCSS with tailwindcss-transitions

    Hey,

    Awesome plugin...I am having trouble figuring out the best way to configure purgeCSS to not delete this:

    /* base styles for the default transition duration, timing function, and delay (when they differ from the CSS defaults) */
    *, *::before, *::after {
      --transition-duration: 250ms;
      /* when the default timing function is a value other than "ease": */
      --transition-timing-function: [default-timing-function];
      /* when the default delay is a value other than zero: */
      --transition-delay: [default-delay];
    }
    

    I have the standard configuration for tailwind with purgeCSS and I can't think of exactly how to whitelist this specific part I guess I could fork and wrap that in a purgeCSS ignore but maybe that should be the default? Or maybe you can think of a way to whitelist that part of it.

    Cheers!

  • 5

    global default transition-property & transition-duration aren't utility-first

    tailwindcss-transitions sets base styles for transition-property & transition-duration like this:

    *, *::before, *::after {
      transition-property: none;
      transition-duration: 250ms;
    }
    

    In my opinion it's against utility-first because every element gets those base styles even though they may not even need it. And that might cause an uncontrollable behavior in some cases.

    Is there a better approch for this?

  • 6

    Apply transition with custom components [@apply]

    Is` there a way to apply the transition to extracted css classes with [@apply]?

    .btn {
        @apply bg-indigo-600 text-indigo-100;
    }
    
    .btn:hover {
        @apply bg-indigo-300 text-indigo-900;
    }
    
    /* .btn transition 
    transition-bg transition-text
    */
    
  • 7

    Support: Not creating base styles

    I'm fairly new to Tailwind so apologies if this is an ignorant question.

    I install it (npm ...) and have this in my tailwind config file:

    // tailwind.config.js
    module.exports = {
        theme: {
            extend: {
                colors: {
                    'hyperia-blue': '#02C4D9',
                },
                fontFamily: {
                    'display': ['Roboto', 'sans']
                },
            },
            plugins: [
                require('tailwindcss-transitions')(),
            ],
        },
    }
    

    When I run npm run watch there are no transition classes in my base.css. What am I doing wrong?

    Thanks.

  • 8

    Can't extend plugin's properties without rewriting all of them

    I'm using the latest version of tailwindcss and tailwindcss-transitions. When I use the theme: { extend:{} } syntax to add, as an example, a "margin" transitionProperty, the resulting compiled css will only contains the .transition-margin utility.

    Example code: theme: { extend: { transitionProperty: { 'margin': 'margin' } } }.

    Am I doing something wrong? I'm using the same syntax for the core values of tailwindcss and it's working as intended by adding new values and replacing existing ones without deleting the other pre-existing ones.

  • 9

    Bump lodash from 4.17.11 to 4.17.13

    Bumps lodash from 4.17.11 to 4.17.13.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot ignore this [patch|minor|major] version will close this PR and stop Dependabot creating any more for this minor/major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language
  • 10

    Is it possible to change the default class that is created?

    I frequently utilize :before and :after to generate gradient animations. I believe there should be an option to add those selectors into baseStyles. It's not a huge deal, but I'm used to only declaring transition-all so I almost always forget to on these classes.

    I personally think the default should be *, *::before, *::after. I believe that would get all visual elements where a transition is possible.

  • 11

    Bump acorn from 6.4.0 to 6.4.1

    Bumps acorn from 6.4.0 to 6.4.1.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.