How to dynamically populate tailwindcss grid-cols-x property?
Asked Answered
M

2

6

I am currently working on a page using NextJs and TailwindCss. The user has the ability of loading an image locally and setting the number of pieces horiz/vert (rows/cols) that they wish the image to be split in. To properly display this, I need to set the grid to the proper number of columns in the parent element.

I have an API I call locally that uses sharp to perform the split and calculate the width and height and I sort the images in my array so that they are in order since it is async. I then also generate a dynamic class string that just populates the proper number of columns for later assignment to my parent grid elements class.

CLASS STRING POPULATION

const gridClass = `grid grid-cols-${numCols} gap-2 pt-2`;

//*** At this point, the value of gridClass, if columns were set to 3, using template literals is :

'grid grid-cols-3 gap-2 pt-2'

//The proper string is now populated and passed back in the API response via classCss key

res.status(200).json({ msg: 'Success splitting', tileData: tiles, classCss: gridClass})

PAGE SNIPPET:

<div id="final">
  <div className={tileCss} > //<--This is where I pull in the generated class string
    {
      imageData.map((nft, i)=>(
        <div key={i} className='border shadow rounded-x1 overflow-hidden'>
          <Image src={nft.imgSrc}  alt="image" layout="responsive" width={nft.tileDimX} height={nft.tileDimY}/>
        </div>
       ))
     }
   </div>
</div>

This sometimes works but other times it doesn't. Usually if I set the columns to 3, it seems to work properly, but if I set it to 5 lets say, regardless of the input image size, it just puts them all in a single column with large images. Oddly however, the parent grid class on the page is correct, it just seems that it isn't adhered to. I will provide some snapshots below to show what I'm talking about. I've been trying to figure this out for a couple days, however I haven't had luck and since I'm new to NextJs I thought I would share here and see if I'm just doing something stupid. Thanks!

The below results also don't seem to care if the viewing window is stretched wide or reduced in size. I just took the snapshots below so that you could see what was happening in a smaller viewing window.

This is the expected result where the image columns should match the columns entered by the user:

Proper display of page

Html when working

Notice how the css class shows up under styles as well:

Proper styles

This is the improper result, where the user selected 5 columns, the image was split into the correct number of columns, but the display of this in the front end grid does not follow the css.

Improper display of image

As you can see grid-cols-5 is correct from a class standpoint, but the viewed result doesn't adhere to this.

Html when not working

Grid-cols-5 is in html class but missing under styles applied:

Missing under styles

Mac answered 16/5, 2022 at 14:3 Comment(0)
M
21

So I finally found the source to the issue. It seems that tailwindcss performs an optimization on classes brought in and if you are not using the class anywhere in your html, it doesn't include those classes. So I not only needed to return my dynamic string with the expected class, but I also needed to add all the classes I would possibly be using into my tailwind.config.js file under the safelist key.

So my config now looks like this and it is working as expected:

module.exports = {
  content: [
    './pages/**/*.{js,ts,jsx,tsx}',
],
safelist: [
  {
      pattern: /grid-cols-./,
  }
],
  theme: {
    extend: {},
  },
  plugins: [],
}

More information can be found here: https://tailwindcss.com/docs/content-configuration#using-regular-expressions

Thanks again Mohit for your assistance.

Mac answered 17/5, 2022 at 18:20 Comment(0)
P
-2

One of the problem I noticed is in grid-cols-${numCols} in the line

const gridClass = `grid grid-cols-${numCols} gap-2 pt-2`;

TailwindCSS doesn't allow you to generate classes dynamically. So when you use the following to generate the class… grid-cols-${numCols} as a string.

…TailwindCSS will not pick that up as a valid TailwindCSS class and therefore will not produce the necessary CSS.

You can use the function from where you are getting numCols and instead of returning the value of numCols, simply return grid-cols-${numCols}.

Suppose let say your function be getNumofCols(), then modify it like this

function getNumofCols() {
  ...
  ...
  ...
  ...
  ...
 
  return "grid-cols-" + numCols ;
}

So that it returns the complete string .

And use it like again

const gridClass = `grid ${getNumofCols()} gap-2 pt-2`;

If your function uses any parameter then you can create a new function and call this function and just add grid-cols- to the return value.

By doing it this way, the entire string for every class is in your source code, so Tailwind will know to generate the applicable CSS.

Pusher answered 17/5, 2022 at 6:3 Comment(4)
Thanks Mohit for the reply! I am a little confused and I just want to be sure I understand the issue. In my API response I have this: const gridClass = grid grid-cols-${numCols} gap-2 pt-2; which then assigns "grid grid-cols-3 gap-2 pt-2" to gridClass if the columns were set to 3. So when my response is sent grid class is populated correct. res.status(200).json({ msg: 'Success splitting', tileData: tiles, classCss: gridClass}) If you look at the HTML screenshots of the class under the "final" id you will see the proper entry there. What point does tailwind process in the pipe.Mac
I have modified the question slightly under the CLASS STRING POPULATION entry above to add a bit more clarification and information as I never stated that gridClass is populated already using template literals with the proper values when being sent back in the response.Mac
You have to simply return the number of columns as string, so that tailwind can recognise it.Pusher
I am returning it as a string in my API. My API return value is 'grid grid-cols-3 gap-2 pt-2' for the classCss. Then using react state I assign that string to tileCss and that is what I reference in the page. Do I need to handle the page population differently?Mac

© 2022 - 2024 — McMap. All rights reserved.