Change styles if content crosses first line Tailwind-CSS - reactjs

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>

Related

How can I add media queries like Tailwind to be in HTML but without Tailwind In React?

For example : with Tailwind:
<div className="md:hidden">Hello</div>
will result the div hidden after the breakpoint md - which after Tailwind doc , it is 768px;
I would like to be able to do the same, but for custom widths, so not 768px;
And I Don't want to write it in the CSS file and I dont want to modify Tailwind files.
I would like to be still inline . Is it possible?
Documentation
If you need to use a one-off breakpoint that doesn’t make sense to include in your theme, use the min or max modifiers to generate custom breakpoint on the fly using any arbitrary value.
<div class="min-[320px]:text-center max-[600px]:bg-sky-300">
<!-- ... -->
</div>

Dynamic var width inside Tailwind className [duplicate]

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

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.

React - multiple properties on an inline style for filter

Is it possible for the filter property, applied to a styles object in React to have multiple filter values set?
saturation = 25;
blurAmount = 5;
brightness = 25;
opacity = 0.85;
let styles = {
backgroundImage: `url(${imageUrl})`,
WebkitFilter: `brightness(${brightness}%) saturation(${saturation}%) blur(${blurAmount}px)`,
filter: `brightness(${brightness}%) saturation(${saturation}%) blur(${blurAmount}px)`,
opacity: opacity
};
In the code above, only the opacity and backgroundImage properties get set correctly when I add the inline style to my component.
React does not support all the CSS properties so my best suggestion is you can use 3rd party library like this one https://github.com/iyegoroff/react-native-color-matrix-image-filters#supported-filters
checkout this lib I think this will help you.
I a solution I found was to give the element an ID, and set the ID to something that's associated with the color.
Example:
<img id={Log.serv} src="RadioWaves.png"/>
Log is a variable, that has dynamic input. Serv being severity (the color).
Now what you can do is on a CSS sheet, you can apply the filter to elements that have that ID.
Example:
#AllSystemsGo{
filter: invert(95%) sepia(79%) saturate(992%) hue-rotate(33deg) brightness(103%) contrast(98%);
}
You could substitute an ID with a separate classname, either way, works. I did not want to install a separate lib, so this what I came up with.

How to deal with reactjs adding a surrounding div to my component?

Reactjs adds a surrounding div to my component that breaks my layout. I want The text "Balance" and the amount to be on the same line.
<span>Balance:</span>
<div id="Balance-react-component-7c517694-f02f-4cbb-aee1-08a98f7ea145">
<span data-reactroot="" class="balance">$3.00</span>
</div>
I know I could just have the component return the entire text, including the word Balance, but I don't want to do that. How do I stop react from outputting this div, or at least make it a span instead so it doesn't force a line break?
react_component("Balance",
:html_options => {:style => "display:inline-block"}
)
Was a case of RTFM, I found the solution is to use the html_options parameter to pass a style to the surrounding div. (Can also pass a class as well and style it that way.)

Resources