Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature discussion] Add variants through plugins #496

Closed
adamwathan opened this issue Jun 19, 2018 · 11 comments
Closed

[Feature discussion] Add variants through plugins #496

adamwathan opened this issue Jun 19, 2018 · 11 comments

Comments

@adamwathan
Copy link
Member

Was brainstorming a bit on what it might look like to support adding new variants (hover, focus, etc) through the plugin system.

Here's a bit of code exploring what that API might look like:

function ({ addVariant }) {
  // Simple selector change
  addVariant('even', function (className) {
    return `.even\\:${className}:nth-child(even)`
  })

  // Multi-part selector
  addVariant('group-hover', function (className) {
    return `.group:hover .group-hover\\:${className}`
  })

  // Another multi-part selector
  addVariant('children', function (className) {
    return `.children\\:${className} > *`
  })

  // Change selector and modify properties
  addVariant('important', function (className, properties) {
    return {
      [`.${className}\\!`]: {
        ..._.map(properties, (value) => `${value} !important`)
      },
    }
  })

  // Variant that needs to all be wrapped in an at-rule (note optional third arg)
  addVariant('supports-grid', function (className) {
    return `.supports-grid\\:${className}`
  }, '@supports (display: grid)')
}

Anything anyone can think of that would be useful to support that this API couldn't handle?

@benface
Copy link
Contributor

benface commented Jun 19, 2018

Would it be possible to define where the variant rules will appear in the compiled CSS? Maybe at least an option between before and after the default rules?

@adamwathan
Copy link
Member Author

Would it be possible to define where the variant rules will appear in the compiled CSS? Maybe at least an option between before and after the default rules?

So as part of this feature, my plan is to make generated variant order mirror the order in the modules section of the config file.

So if you have:

modules: {
  // ...
  backgroundColors: ['responsive', 'hover', 'focus'],
  borderColors: ['responsive', 'focus', 'hover'],
}

...focus variants would be generated before hover variants for border colors, but the opposite would be true for background colors. The responsive variant is sort of a special case in that those variants are always inserted at the end of your CSS (or wherever you've put the @tailwind screens at-rule), but everything else would follow the order in your config for maximum control and flexibility.

@benface
Copy link
Contributor

benface commented Jun 22, 2018

@adamwathan So all variants would be generated after the default/normal rules? Unless I’m misunderstanding, that would be a problem for the children variant, since you wouldn’t be able to override a child’s style as I explained in #277. Example:

<ul class="list-reset children:block children:rounded-full children:bg-black">
    <li>
        1
    </li>
    <li class="bg-red"> <!-- bg-red will be overridden by children:bg-black -->
        2 (selected)
    </li>
    <li>
        3
    </li>
</ul>

@adamwathan
Copy link
Member Author

I think we could solve that by adding an optional normal/plain/default variant that you could add to the list to control where the unmodified utilities are generated, and if it's not present we just push it onto the beginning of the list.

@benface
Copy link
Contributor

benface commented Jun 22, 2018

@adamwathan You always come up with the most thoughtful solutions. :)

@Anachron
Copy link

Anachron commented Jun 30, 2018

You have even ... why not have odd as well?

@adamwathan
Copy link
Member Author

This isn't about adding even, it's about adding the ability for people to create their own variants, and I'm using even as an example to explain the API.

@Anachron
Copy link

Sorry very new to tailwindcss and didn't understand the new API at first. Yeah,- totally would be useful!

@Benecke
Copy link

Benecke commented Jul 12, 2018

Boy oh boy, I'm exited! Came here looking for something this! Is it what I need? Not sure...let me explain.

tldr: I need different layouts based on custom app states which are defined by a css class on a parent element (e.g. the body element) – a common usecase for websites/components, I think?

Details:

I've got a big header on my site for desktop. On tablet and downwards this header will become a minimal version of itself. Mobile nav menu, no searchbar, you name it. No problem as this can be done with tailwind.

However, the header has two states: static and fixed position. So I threw in the some JS for recalculation/offset and set a body class to make it fixed: has-fixed-header. While the header is in that fixed position state, I'd like to visually reduce it to the aforementioned minimal version (to save vertical screen space).

I'm currently doing those extensions myself:

.has-fixed-header {

  .has-fixed-header- {

    &block {
      @apply .block;
    }

    &hidden {
      @apply .hidden;
    }

    &w-3-5 {
      @apply .w-3-5;
    }
  }
}

Obviously, a mixin/function would help but I stopped here because I found your post. 👍 Also, if you exchange has-fixed-header with has-state-yxz it's probably easier to understand what the benefits are.

So yes, @adamwathan, totally upvoting your idea here! Is it even possible to use your code right now?

As you can see from the example, I think I'd also need an option to make a prefix class like has-fixed-header-block only apply when the outer wrapper class has-fixed-header is set.

Basically, something like the functionality of tailwinds group group-hover variant classes.

I think this is going into the right direction however. Again, so happy I met tailwind (great name by the way)!

Sidenote: I changed the separator from : to - inside tailwinds options (due to a problem with grunt/purgecss). This is why I'm not using colons like .has-fixed-header: in the code example.

@nathanchicken
Copy link

This is a feature I'd like - I'll try it out when I can. I'd like to use it in conjunction with something like https://github.com/ten1seven/what-input

I want to stay responsible with focus states and not really change them and yet our designers can't deal with blue rings around every button. Nor do I want to just change all focus states as it becomes hard to strike a balance between mouse-hover and mouse-focus sometimes. We're going to need some nuance in our focus styles, so I was wondering if we could have something liek focus:... for most cases as normal...and focus-mouse:..., maybe even focus-keyboard:...

I could then also write a class (somewhere in my sass) like this:

[data-whatintent='mouse'] [class*="focus-mouse"]:focus { outline:none }

...which would, when mouse is being used, remove focus outlines where I've thought to put some sort of mouse-focus state (so that I'm never accidentally removing all kind of focus guidance).

It's long winded, but such is the situation.

@adamwathan
Copy link
Member Author

This feature is implemented now (at least in a basic state) so closing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants