Tailwindcss: Make it possible to specify what config object Tailwind should use as its starting point

Created on 21 Feb 2019  Â·  9Comments  Â·  Source: tailwindlabs/tailwindcss

Starting a new discussion around an idea originally posted in #674.

Everything that follows was originally posted by @bradlc in https://github.com/tailwindcss/tailwindcss/pull/674#issuecomment-466092898


Or maybe there could be different base configs to start from and extend? default for the "recommended" utilities and full for ALL of them.

What do you think about having an explicit extends key in the config? For example:

module.exports = {
  // `tailwindcss/{default,recommended,full}` etc. or `@mycompany/tailwind`
  extends: require('tailwindcss/default'),
  theme: {
    // ...
  }
}

This has a few benefits I think. One being that it is much more clear that there is a merge going on. I think that the new stripped-down default config could be a source of confusion for people new to Tailwind. Adding extends makes it clear that there’s _something_ going on, and would go a long way to avoiding confusion in my opinion.

It also means you have the choice to opt-out of the merge completely (just remove the extends), or create your own shareable config (e.g. @mycompany/tailwind)

feature request

Most helpful comment

As you know I am a big fan of plugins reading from the theme, because it allows you to keep all of your theme values in one place.

I love the idea of plugins that essentially register new modules...

@bradlc Yeah the more I think about it the more I think you're right — it's more flexible and consistent if we encourage that plugins claim a key in your theme instead of configuring them directly. Plugins could make this key customizable if needed for namespace collision reasons, but I bet in practice it would just work. I'm going to update all of the core plugins to source their configuration from the theme/variants sections themselves instead of being configured directly 👍🏻

An alternative to having an extends key is to allow a config to be an array, like in this ESLint proposal.

@bradlc The only thing I don't like about this is that you'd have to list it by default for every project (at least any time you create a config file), and the fact that we have all these corePlugins baked in sort of makes it seem odd to treat the default config like a disposable thing by forcing the user to specify it by default.

I think I prefer the idea of supporting an array in the extends key, like this:

module.exports = {
  extends: [
    require('tailwindcss/default-config'),
    require('@my/defaults'),
  ],
  theme: {
    // ...
  }
}

You'd still be required to specify the default config if you wanted to preserve it while also applying another config on top, but this way users could still make simple changes to the config without having to use an array at the root level and always specifying the default config. Put another way, I like that the default config is the base config by default, and that you don't have to list it explicitly.

I like this idea a lot though, might not make it in for 1.0 because I don't want to keep pushing it back, but I can't see why it wouldn't be easy to add in 1.1 without breaking anything.

All 9 comments

Originally posted by @adamwathan (me!) in https://github.com/tailwindcss/tailwindcss/pull/674#issuecomment-466149126


My only real hesitation with the extends thing is that there's nothing really stopping you from solving it with Just JavaScript™ already:

// Brad's idea
module.exports = {
  extends: require('@mycompany/tailwind-theme'),
  theme: {
    colors: { ... },
    extend: {
      spacing: { ... },
    },
  },
}

// Just JavaScript™
module.exports = {
  theme: require('@mycompany/tailwind-theme')({
    colors: { ... },
    extend: {
      spacing: { ... },
    },
  }),
}

You'd just need to write some merging logic. It's still kinda interesting though, maybe there are other things you could do with the extends approach that make it more useful than trying to solve it in user land with just JS.

Would be interested in discussing the idea in more detail in a separate issue 👍

The more I think about this the more I like it to be honest. Tailwind is already using a default configuration that you are extending by creating your own tailwind.config.js file. This idea just lets you configure what object Tailwind should be applying your customizations against.

Basically it's as if the default Tailwind config has:

module.exports = {
  extends: require('tailwindcss/default-config'),
  // ...
}

...baked in by default, and you are just overriding that key just like anything else.

If we add support for this I think it makes sense for extends to reference an entire config object, not just a theme. That way you could extend another base config that already had plugins enabled or something if you wanted as well, although I'm not sure how you would configure them. I guess by having the plugin read from the theme key instead of being configured directly.

Thanks for creating a separate issue @adamwathan!

If we add support for this I think it makes sense for extends to reference an entire config object, not just a theme. That way you could extend another base config that already had plugins enabled or something if you wanted as well, although I'm not sure how you would configure them. I guess by having the plugin read from the theme key instead of being configured directly.

Absolutely. You’re right though, configuring plugins could get weird in that case. As you know I am a big fan of plugins reading from the theme, because it allows you to keep all of your theme values in one place.

I love the idea of plugins that essentially register new modules:

// @mycompany/tailwindcss
module.exports = {
  extends: require('tailwindcss/default-config'),
  plugins: [
    function alpha({ config, addUtilities }) {
      let alpha = config('theme.alpha', {})
      let variants = config('variants.alpha', [])
      // ..now use those to generate utilities
    },
    // ..loads more of these
  ]
}
// tailwind.js
module.exports = {
  extends: require('@mycompany/tailwindcss'),
  theme: {
    alpha: {
      '10': 0.1,
      '20': 0.2
    },
    // ...
  },
  variants: {
    alpha: ['responsive', 'hover']
  }
}

I also think that having first-class support for something like this could help encourage further development of the Tailwind ecosystem. Having to write custom merge logic is enough to discourage most people.

This is such a cool idea ✨ The only thing I can add is that extends should accept both a string and an array to allow users to extend from multiple configs (eg. Tailwind's defaults -> user defaults -> project config).

Yeah definitely! An alternative to having an extends key is to allow a config to be an array, like in this ESLint proposal. So you would have:

module.exports = [
  require('tailwindcss/default-config'),
  require('@my/defaults'),
  {
    // project config here
  }
]

As you know I am a big fan of plugins reading from the theme, because it allows you to keep all of your theme values in one place.

I love the idea of plugins that essentially register new modules...

@bradlc Yeah the more I think about it the more I think you're right — it's more flexible and consistent if we encourage that plugins claim a key in your theme instead of configuring them directly. Plugins could make this key customizable if needed for namespace collision reasons, but I bet in practice it would just work. I'm going to update all of the core plugins to source their configuration from the theme/variants sections themselves instead of being configured directly 👍🏻

An alternative to having an extends key is to allow a config to be an array, like in this ESLint proposal.

@bradlc The only thing I don't like about this is that you'd have to list it by default for every project (at least any time you create a config file), and the fact that we have all these corePlugins baked in sort of makes it seem odd to treat the default config like a disposable thing by forcing the user to specify it by default.

I think I prefer the idea of supporting an array in the extends key, like this:

module.exports = {
  extends: [
    require('tailwindcss/default-config'),
    require('@my/defaults'),
  ],
  theme: {
    // ...
  }
}

You'd still be required to specify the default config if you wanted to preserve it while also applying another config on top, but this way users could still make simple changes to the config without having to use an array at the root level and always specifying the default config. Put another way, I like that the default config is the base config by default, and that you don't have to list it explicitly.

I like this idea a lot though, might not make it in for 1.0 because I don't want to keep pushing it back, but I can't see why it wouldn't be easy to add in 1.1 without breaking anything.

Can add this if people still want it and start asking for it but no activity on this in well over a year without us adding it so just going to close for now. Not too complicated to implement though if there's demand for it.

I'm in desperate need of this functionality because I would like to start on a clean slate but I still have to keep the old config file in use. With this, I could use two configs and start clean with a new setup.

We would also like this at J&J so that we can create a brand config which can be extended at the individual site/market level.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ghost picture ghost  Â·  3Comments

spyric picture spyric  Â·  3Comments

jvanbaarsen picture jvanbaarsen  Â·  3Comments

paulhuisman picture paulhuisman  Â·  3Comments

chintanbanugaria picture chintanbanugaria  Â·  3Comments