Giter Site home page Giter Site logo

Overlapping classes about twind HOT 12 CLOSED

tw-in-js avatar tw-in-js commented on August 22, 2024
Overlapping classes

from twind.

Comments (12)

sastan avatar sastan commented on August 22, 2024 1

There are several ways to solve this:

  1. use ! as modifier (docs)
<Button className="bg-red-600!">red</Button>

Demo

Maybe this should be more prominent in the docs.... ๐Ÿ˜‰

  1. Use a dedicated property
function Button({ bgColor = "blue-600", className, children }) {
  return (
    <button className={tw`border text-white bg-${bgColor} ${className}`}>{children}</button>
  );
}

<Button>blue</Button>
<Button bgColor="red-600">red</Button>

One remark on performance: Try to use the template literal syntax as it allows to cache the static parts (tw will ignore falsey values):

function Button({ className = "", children }) {
  return (
    <button className={tw`border text-white bg-blue-600 ${className}`}>{children}</button>
  );
}

PS: We are working on a styled component like API: #7 . Maybe you have thoughts or some input there as well.

from twind.

sastan avatar sastan commented on August 22, 2024 1

I'm closing this for now. But feel free to re-open if needed...

from twind.

just214 avatar just214 commented on August 22, 2024 1

It's declarative, clearly defined in the rendered markup, and it works exactly as it should as far as I can tell. I think this is great!

from twind.

lukejacksonn avatar lukejacksonn commented on August 22, 2024 1

Nice, I'm not against that at all!

from twind.

sastan avatar sastan commented on August 22, 2024

We are planing to add a best practices guide. These kind of questions are very important to use. Thank you.

Your demo could be written like this for optimal performance (only meant for future reference):

using inline plugins: Demo

import { tw } from 'https://cdn.skypack.dev/twind'

const shared = ({ tw }) => tw`h-40 border(2 red-100)`
// const shared = tw`h-40 border(2 red-100)`

const topClassName = tw`${shared} bg-red-400`
const bottomClassName = tw`${shared} bg-purple-400`

document.body.innerHTML = `
  <div class="${topClassName}">
    should be red
  </div>
  <div class="${bottomClassName}">
    should be purple
  </div>
`

using base style with ! overrides: Demo

import { tw } from 'https://cdn.skypack.dev/twind'

const baseClassName = tw`h-40 border(2 red-100) bg-red-400`
const bottomClassName = tw`${baseClassName} bg-purple-400!`

document.body.innerHTML = `
  <div class="${baseClassName}">
    should be red
  </div>
  <div class="${bottomClassName}">
    should be purple
  </div>
`

Please let us know what to think, if you have any more questions or improvements (API, docs) you like to see.

from twind.

just214 avatar just214 commented on August 22, 2024

Hi all,

twind authors- Brilliant work! ๐Ÿ‘

As for overlapping classes..this is a problem I also often encounter when creating sharable React components using Tailwind. I think it's a very common scenario to want to provide default classes that are easily overridable at an instance level. It seems like the Tailwind docs encourage component abstractions, but at the same time, you canโ€™t pass text-blue-500 to a component that has a competing text color class already defined (as an example). You would expect the last-defined className to win, but this is not usually the case.

For myself, custom props to define styles are not an ideal solution. I think ! is an okay solution from the userโ€™s perspective, but it requires the use of important!, which is probably best reserved for more dire situations.

I would love to see the compiler handle smart merging of competing classes as a first-class feature. I realize that this is not easy and there are lots of considerations like how to handle variants and similiar directives. But, it would be really nice not to have to think about it!

A (possibly bad) idea that came to mind:

A custom default variant.

  • More declarative
  • Possibly easier to parse?
// Reusable Button Component 
const Button = ({children, className, ...rest}) => {
  const mergedClassNames = tw`default:text-blue-500 text-xl ${props.className}`;
  // or tw`text(default:blue-500 xl) ${props.className}`;

  return (
    <button className={mergedClassNames} {...rest}>
      {children}
    </button>
  )
}

// Using the Button 
const App = () => (
  <Button className={tw`text-purple-500`}>Purple Wins</Button>
)

from twind.

sastan avatar sastan commented on August 22, 2024

Thanks for the detailed description.

I don't know if we can ever support default or resolving of overlapping classes. The problem is that text-* is not only for color but used for a lot of different styles. This would mean that the parser or translator needs to have deep knowledge about what CSS styles a plugin generates for a directive and de-duplicates those based on the CSS properties in the resulting CSS object.

Additionally this would introduce another presedence dimension: the order directives are written.

We have two user-land solutions for this kind of problem:

  1. Use ! as modifier
  2. Use a dedicated property color property

I can understand why you would like an integrated solution for this.

Please investigate further and keep use informed about your findings.

from twind.

just214 avatar just214 commented on August 22, 2024

Thanks for the response. Iโ€™ve tried to implement something similar in the past so I definitely understand the challenges. My thought was that the use of the default variant could help in narrowing down the type of competing class names (text-blue-500 vs text-xl for example). But, even then, you would need to generate all the available options on the fly or keep a list in memory.

Either way, I appreciate the consideration and all the work youโ€™ve put into this awesome project!

from twind.

sastan avatar sastan commented on August 22, 2024

After a good night sleep i had an idea: an override variant (name to be discussed) - this variant would increase the selector specificity on rules it is applied to.

tw`text-blue-500`
// => .text-blue-500 { ... }

tw`override:text-purple-500`
// => .override\:text-purple-500.override\:text-purple-500 { ... }

This could be used like this:

const Button = ({ children, className, ...props }) => {
  const mergedClassNames = tw`text-blue-500 text-xl override:(${props.className})`
  return (
    <button className={mergedClassNames} {...props}>
      {children}
    </button>
  )
}

const App = () => (
  <Button className="text-purple-500 text-2xl">Purple and 2xl win</Button>
)

@mfolnovic @gojutin Would that help?

from twind.

sastan avatar sastan commented on August 22, 2024

This can already be implements in user-land:

Demo

setup({
  variants: {
    ':override': '&&',
  },
})

const Button = ({ children, className, ...props }) => {
  const mergedClassNames = tw`text(blue-500 xl) override:(${props.className})`
  return (
    <button className={mergedClassNames} {...props}>
      {children}
    </button>
  )
}

const App = () => (
  <Button className="text(purple-500 2xl)">Purple and 2xl win</Button>
)

I'm open to to integrate this into twind. But we should maybe come up with a better name.

@lukejacksonn What do you think?

from twind.

lukejacksonn avatar lukejacksonn commented on August 22, 2024

I concur. Simple, elegant solution that requires no changes to core, love it!

from twind.

sastan avatar sastan commented on August 22, 2024

@lukejacksonn I just have updated the styled PR and found that this override variant might be useful there as well. We should think about adding this to the core.

from twind.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.