Search code examples
htmlcssreactjstailwind-csscss-grid

tailwind grid issue React (responsive col-span showing in HTML but not working as expected)


I have a grid that should be doing what I want. This is a jsfiddle of the behavior I'm expected. It depends on this responsive code: col-span-3 md:col-span-2 for instance for one of the items.

Here is the issue: I check the HTML of the page, and my dynamic breakpoint col-spans are showing. So it should be doing what I expect. However, they are not assuming the md: col-span when the viewport expands. What could be the issue?

Here is the wrapper for my component:

<div className="max-w-5xl">
        <div className="grid grid-cols-6 gap-10 p-6">
          {
            supportedArray.map((card, idx) => <SupportCard key={idx} {...card} />
          )}
        </div>
</div>

Here is my component:

import { ISupportCard } from "~/types"

const SupportCard = (card: ISupportCard) => {
  return (
    <div className={`bg-white card shadow-xl aspect-[portrait] overflow-hidden rounded-t-xl rounded-b-3xl col-span-${card.mobileSpan} md:col-span-${card.colSpan} ${card.customClasses ?? ""}`}>
      <div className="relative">
        <img className={`w-full h-full object-cover ${card.imgClasses ?? ""}`} src={card.image} alt={card.alt_text ?? card.title} />
        <h3 className="absolute text-neutralBlack bottom-0 flex justify-center items-center text-lg md:text-2xl font-bold bg-[rgba(255,255,255,0.5)] w-full card-title p-3 backdrop-blur">{card.title}</h3>
      </div>
      <div className="relative card-body hidden md:flex flex-1">
        <p className="text-xl font-medium">{card.copy}</p>
      </div>
    </div>
  )
}

export default SupportCard

Here is the shape of the data coming in:

export interface ISupportCard {
  imgClasses?: string
  colSpan: number
  mobileSpan: number
  customClasses?: string
  title: string
  image: string
  alt_text?: string
  copy: string
}

Here is one of the objects:

{
    colSpan: 6,
    mobileSpan: 3,
    imgClasses: "aspect-square md:aspect-auto object-[40%] md:object-fill",
    title: "Organizations",
    image: "/images/cards/support-organizations.jpg",
    alt_text: "Organizations",
    copy: `Copy...`
  }

Solution

  • As per the documentation:

    The most important implication of how Tailwind extracts class names is that it will only find classes that exist as complete unbroken strings in your source files.

    If you use string interpolation or concatenate partial class names together, Tailwind will not find them and therefore will not generate the corresponding CSS:

    Don’t construct class names dynamically

    <div class="text-{{ error ? 'red' : 'green' }}-600"></div>
    

    In the example above, the strings text-red-600 and text-green-600 do not exist, so Tailwind will not generate those classes. Instead, make sure any class names you’re using exist in full:

    Always use complete class names

    <div class="{{ error ? 'text-red-600' : 'text-green-600' }}"></div>
    

    You could:

    • Have a dictionary for col-span-* to Tailwind class names:

      const SupportCard = (card: ISupportCard) => {
        const COL_SPANS = {
          1: 'col-span-1',
          2: 'col-span-2',
          // …
        };
        const MD_COL_SPANS = {
          1: 'md:col-span-1',
          2: 'md:col-span-2',
          // …
        };
        // …
        return (
          <div className={`… ${COL_SPANS[card.mobileSpan]} ${MD_COL_SPANS [card.colSpan]} …`}>
      
    • Use the style attribute for truly dynamic properties:

      const SupportCard = (card: ISupportCard) => {
        return (
          <div
            className={`… md:col-span-[--md-col-span] …`}
            style={{
              gridColumns: `span ${card.mobileSpan} / span ${card.mobileSpan}`,
              '--md-col-span': `span ${card.colSpan} / span ${card.colSpan}`,
            }}
          >
      
    • safelist the classes, if you have a limited number of known spans:

      module.exports = {
        safelist: [
          { pattern: /^col-span-[1-6]$/ },
          {
            pattern: /^col-span-[2-4]$/,
            variants: ['md'],
          },
          // …
        ],
        // …
      ];