Dynamic var width inside Tailwind className [duplicate] - reactjs

I'm trying to make a react component that changes the width from a parameter but it's doesn't work and I don't know why.
function Bar() {
const p =80
const style = `bg-slate-500 h-8 w-[${p.toFixed(1)}%]`
console.log(style)
return (
<div className=' h-8 w-full'>
<div className={`bg-slate-500 h-8 w-[${p}%]`}>
</div>
</div>
)
}
export default Bar
With this code I get a full-size bar, but if I use a strict String with 80.0 it works fine

The other answers are wrong. In Tailwind V3 JIT is included and you won't need to set mode to jit anymore. And even in Tailwind V2 the posted code wouldn't work.
Following the docs, you must avoid string interpolation and use complete class names.
This is wrong:
<div class="text-{{ error ? 'red' : 'green' }}-600"></div>
Instead use Complete class names:
<div class="{{ error ? 'text-red-600' : 'text-green-600' }}"></div>
What about using inline styles?
You may be tempted to use inline styles, but remember Content Security Policies are increasingly under scrutiny to disallow unsafe inlines. Any inline style or script could in theory be injected with unintended content. Furthermore, the whole point to Tailwind is to generate CSS at build time, so you'd be working around it and might as well not even be using it in this case.

in tailwind.config.js add mode: 'jit'.
I would suggest https://v2.tailwindcss.com/docs/just-in-time-mode to learn more.
e.g:
module.exports = {
//other options
mode: 'jit',
}

I ran into a similar issue building a site with Astro & Tailwind.
The solution I discovered was to use the 'safelist' feature that allows you to define certain classes that will be force-compiled, regardless of whether or not they are found when scanning the specified content locations in the tailwind.config.cjs file.
An example of the code I used to fix my situation:
module.exports = {
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],
Adding a safelist and classes to it:
safelist: ["lg:grid-cols-[1fr_4fr]", "lg:grid-cols-[1fr_3fr_1fr]"],
...
Here's a link to the relevant area in the Tailwind documentation.

If your p's value is a constant that will be used across the app, you can instead define it in your tailwind.config.js file like this.
theme: {
extend: {
spacing: {
"p-value": "80%",
},
},
}
Then you can modify your code to this.
<div className="bg-slate-500 h-8 w-p-value">

Include mode: 'jit' in tailwind config file

Related

Tailwindcss v2 not applying the correct style to element (mt-5 styles with 3rem instead of 1.25rem)

Certain styles in my project are not applying correctly. The easiest example to illustrate is mt-5 which according to the docs should be 1.25rem, but instead, my project shows as 3rem.
I've tried going to my tailwind.config.js and adding important: true to it and it does work! But I'm wondering if there's another way to fix this.

access to child element in tailwind reactjs

Could you tell me the way to do something like this in tailwindcss:
first[&>.a-child-class]:text-5xl
I'm trying to style the first element by the way passing classes when it's rendering,I want to change its child's style, but the code above did not work.
I tried to put that classes inside component by default, but I realized, the component need to reusable, so that it is not reasonable.
please help meeeee.
thank you so much, have nice day.
In tailwind 3.1, arbitrary variants can be stacked with built-in modifiers or with each other, just like the rest of the modifiers in Tailwind. You can see the document here. You are missing : after first.
Example:
<div className="first:[&>.a-child-class]:text-5xl">
<p className="a-child-class">first</p>
<p className="a-child-class">second</p>
<p className="a-child-class">third</p>
<p className="a-child-class">forth</p>
</div>
Tailwind Play demo

TailwindCSS & NextJS - Different color mode than Dark

According to TailwindCSS Docs, you can specify color mode by document.body.addClass('dark') and use it on your CSS classnames like dark:text-blue-500.
But there is no option for adding new color modes, i want something like evening, midnight. Any ideas how to implement different color modes without going too much into it?
The most logical way i can think is create a ColorModeContext and export my components according to context but it is kinda hardcoded.
Tailwind 3.1 now includes arbitrary variants which, along with the addVariant plugin, can be used to create custom color modes. Using the css * selector, you can apply a class like evening to an element, and all its children will have apply evening: ... styles.
tailwind.config.js
let plugin = require("tailwindcss/plugin")
module.exports = {
// ...
plugins: [
plugin(function ({ addVariant }) {
addVariant('evening', '.evening *')
addVariant('midnight', '.midnight *')
})
]
}
pages/[some-page].jsx
<div className="evening">
<div className="text-blue-300 evening:text-blue-500"></div>
</div>

Change styles if content crosses first line Tailwind-CSS

I am making messaging app in which I want to create a message whose design looks like this in the following image
I want to have two types of layouts in my messages
If the message is about one line long then it's border-radius should be full // rounded-full
If the message is more then one line then it's border-radius should be md or sm // rounded-md
How can I achieve this design using Tailwind-CSS?
No, CSS can't use number of line as a CSS selector, and so it cannot make a decision in changing the style. ( There is line-clamp property in CSS which can truncates text at a specific number of lines, but I don't think it relates to this question. )
BUT, if you can render each line seperately, you can use css child selector to detect it and apply the tailwind class. Tailwind only provide first-child and last-child modifier so you may need to add extra stylesheet in order to do it.
You may also achieve it by checking the height of the div or counting the length of the words with JavaScript in react, then change the class accordingly.
Example
span:last-child {
#apply rounded-b-md;
}
span:first-child {
#apply rounded-t-md;
}
span:only-child {
#apply rounded-full;
}
I'm afraid the only way to achieve that is by using a little JS.
I guess you are using JS but I cannot guess if u are using some specific framework or library. Btw you need to do some calculations with JS to achieve this behavior. You can do something like:
const fontSize = 16px //default on html
const msgWidth = 50px
const chatMsg = document.querySelector('p.chatMessage-1')
const msg = chatMsg.innerText
chatMsg.classList.add(msg.length * fontsize > msgWidth ? 'border-md' : 'border-full')
One thing you can do is that you can change the styling on the basis of length of message. In one line if you have approx. 20 characters then,
if characters > 20: rounded-sm else: rounded-full
you can do like this.
<span className=`${message.length > 20 ? 'rounded-sm':'rounded-full' } text-base`>{message}</span>

How to dynamically populate tailwindcss grid-cols-x property?

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:
Notice how the css class shows up under styles as well:
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.
As you can see grid-cols-5 is correct from a class standpoint, but the viewed result doesn't adhere to this.
Grid-cols-5 is in html class but missing under styles applied:
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.
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.

Resources