Incorrect component display when passing props and using Tailwind - javascript

I pass the color data to the created component to set a specific color in several places. At the output, it turns out that it is installed only in one place. What could it be? In the project I use only tailwind.
<div className="w-full flex justify-between items-center gap-5">
<FilterButtons dataFilter={""} flag="Artists" color="yellowColor" />
<FilterButtons dataFilter={""} flag="Albums" color="orangeColor" />
</div>
<div className="w-full flex justify-between items-center gap-5">
<FilterButtons dataFilter={filterByCategory} flag="Category" color="orangeColor" />
<FilterButtons dataFilter={filterByLanguage} flag="Language" color="yellowColor" />
</div>
Broadcast props
const FilterButtons = ({ dataFilter, flag, color }) => {
return (
<div className={`w-1/2 flex items-center justify-between px-4 py-2 border border-${color} text-${color} rounded-xl cursor-pointer`}>
<p className={`tracking-1 text-lg`}>{flag}</p>
<MdOutlineKeyboardArrowDown className={`text-4xl`} />
</div>
)
}
Usage in the component
The first block displays a field with a yellow border with black text and with orange texts and a white border
Result
I tried to divide into different variables and set conditions with different flags, nothing changes

You might be having some css specificity issue which is very common with tailwind. But tailwind has a workaround for this.
Use exclamation on the class you want to force a higher specificity for. Example (in your case):
!text-${color}

Related

Template does'nt work with Tailwind in React

If I put the color directly in the tailwind class like "bg-cianTheme" it works. But if i use javascript template like "bg-${primaryColorTheme}" with the code above doesn't work. Why does it happen and how fix ?
The code:
import { BsGithub, BsLinkedin } from 'react-icons/bs'
export interface INewProfileCardProps {
photo: string
github: string
linkedin: string
colors: string[]
primaryColorTheme: string // tailwind refence collor
secondaryColorTheme: String //tailwind reference collor
terciaryColorTheme: string //tailwind reference collor
labelName: string
}
export function NewProfileCard({
photo,
github,
linkedin,
colors,
labelName,
}: INewProfileCardProps) {
const [primaryColorTheme, secondaryColorTheme, terciaryColorTheme] = colors
console.log(`bg-${primaryColorTheme}`)
return (
<div className="flex items-center justify-center">
<div>{/* <p className="text-[250px]">{'<'}</p> */}</div>
<div className=" relative h-[202px] w-[404px] rounded-xl bg-whiteIcon px-4 py-8 pt-2">
<div
className={`bg-${primaryColorTheme} relative flex h-full w-full`}
>
<img
className="absolute bottom-0"
src={photo}
alt="personal-photo"
></img>
</div>
<div className="absolute flex">
<div
className={`flex items-center justify-center font-bold text-${primaryColorTheme} bg-${primaryColorTheme} rounded-l-xl px-6 py-2`}
>
<BsGithub className="text-2xl" />
<p className="ml-3 text-lg">Git Hub</p>
</div>
<div
className={` bg-${secondaryColorTheme} ${primaryColorTheme} flex items-center justify-center rounded-r-xl px-6 py-2 font-bold`}
>
<BsLinkedin className="text-2xl" />
<p className="ml-3 text-lg">Linkedin</p>
</div>
</div>
</div>
<div>
{/* <p className="text-[250px]">
<span className={`text-${primaryColorTheme}`}>/</span>
{'>'}
</p> */}
</div>
</div>
)
}
I try to change the colors with variables in tailwind class with template, but doesn't work.
The problem is the postcss can't find that class when you have interpolated strings like that. You can add this to tailwind.config.js
safelist: ["bg-somecolor"]
or you can find a way to not use interpolation
In addition to pguardiano's answer, you may be able to achieve the same thing by calling the style attribute directly since postCSS only renders what is readily available in the template...
In your case, you can send the hex code directly to the variable and pass it to the style attribute. Example:
<div
className="relative flex h-full w-full"
style="{{ background: primaryColorThemeColor }}"
>
<img
className="absolute bottom-0"
src={photo}
alt="personal-photo"
/>
</div>
If you want to get your hands dirty and do things in a more interesting way, you can take advantage of Tailwind's theming functionality.
It is explained well in this video: https://www.youtube.com/watch?v=MAtaT8BZEAo.
Then you can update your CSS variables with whatever color is coming from your API I guess. Goodluck hacking your way in :)
Ref:
Updating CSS Variables with Javascript: https://css-tricks.com/updating-a-css-variable-with-javascript/

Expand Div smoothly in react with tailwind not happening

I am trying to animate a div containing my input elements which should expand smoothly, the text area at first is small and the other two input and buttons are hidden, when clicking the text area input and button are shown, however there is no transition, just a jump in size, I tried to use framer motion but it doesn't accept the tailwindcss values, putting the transitions class in the parent div didn't help either, can someone please help me with this
<div
ref={mainDivRef}
className='z-10 flex justify-center flex-wrap flex-col gap-2 p-2 bg-slate-300 bg-opacity-30 rounded-md'
onClick={() => handleClickInside()}>
<textarea
className='transition ease-in-out delay-150 resize-none rounded-md p-1 focus:outline-none'
value={mainText}
placeholder={"Ask me something"}
rows={rows}
cols={columns}
onChange={(e) => setmainText(e.target.value)} />
{extraElements &&
<div className='transition-all ease-in-out duration-150 delay-150 inline-flex gap-3 min-w-full'>
<input className='rounded-md p-1 grow focus:outline-none ' type="email" name="sender" id="senderText" placeholder='Your email' />
<button className='rounded-md p-1 bg-blue-200'>Send</button>
</div>
}
</div>
const handleClickInside = () => {
setExtraElements(true)
setRows(10)
setColumns(100)
props.blurBackground(true)
}
Since you're indirectly changing the textarea height/width by changing the rows property, the CSS transitions don't apply. Instead, you need to explicitly set the height of the text area.
For example, you can use CSS inline styles:
<textarea
className='transition ease-in-out delay-150 resize-none rounded-md p-1 focus:outline-none'
value={mainText}
placeholder={"Ask me something"}
style={{ height: `${rows * 10}px`, width: `${columns * 10}px` }}
onChange={(e) => setmainText(e.target.value)} />
As an alternative to framer-motion you can use the Transition component from the #headlessui/react package. It works perfectly with the tailwindcss classes for both entry and exit animations.

Accessing a variable set in one component file in another file React js

I am quite new to react and am trying to create a sports fixture application where when you click on one of the fixtures in the list it takes you to a new page with more things you can do for that fixture.
On my home page I render the list of popular fixtures which I have set in a JSON called popular.json. I have this coded so if I add or remove a fixture from popular.json then this will automatically be rendered by having my component set up as below
import fixtures from './variables/popular.json'
export const setFixture = (id, home, homeLogo, away, awayLogo, date, time, venue) => {
const match = { id: id, teamA: home, teamALogo: homeLogo, teamB: away, teamBLogo: awayLogo, date: date, time: time, stadium: venue }
}
export default function Example() {
return (
<div >
<div className="max-w-4xl mx-auto px-4 py-1 sm:px-6 sm:pt-20 sm:pb-24 lg:max-w-7xl lg:pt-10 lg:px-8">
<h2 className="text-4xl font-bold text-white tracking-tight">
Popular
</h2>
<ul
time="list"
className="grid grid-cols-1 py-10 gap-6 sm:grid-cols-2 lg:grid-cols-3"
>
{fixtures.map((fixture) => (
<li key={fixture.id} className="col-span-1 rounded-lg bg-white bg-opacity-70 hover:bg-gray-100 shadow">
<a href="/game" onClick={setFixture(fixture.home,fixture.homeLogo,fixture.away,fixture.awayLogo,fixture.date,fixture.time,fixture.venue)}>
<div>
<div className="-mt-px flex">
<div className="flex w-0 flex-1">
<div className="mx-auto py-5 flex-shrink-0 flex justify-center">
<img
className="h-16 w-16"
src={fixture.homeLogo}
alt="Logo"
/>
</div>
</div>
<div className="w-1"></div>
<div className="-ml-px flex w-0 flex-1">
<div className="mx-auto py-5 flex-shrink-0 flex items-center justify-center">
<img
className="h-16 w-16"
src={fixture.awayLogo}
alt="Logo"
/>
</div>
</div>
</div>
<div className="-mt-px items-center flex">
<div className="flex w-0 flex-1">
<div className="relative -mr-px inline-flex w-0 flex-1 items-center justify-center rounded-bl-lg border border-transparent py-4 text-3xl font-bold text-gray-600 hover:text-purple-600">
<span className="justify-center">{fixture.home}</span>
</div>
</div>
<div className="flex w-1">
<div className="justify-center flex w-0 flex-1">
<span className="text-4xl font-bold text-center text-gray-600 hover:text-purple-600 tracking-tight">
V
</span>
</div>
</div>
<div className="-ml-px flex w-0 flex-1">
<div className="relative inline-flex w-0 flex-1 items-center justify-center rounded-br-lg border border-transparent py-4 text-3xl font-bold text-gray-600 hover:text-purple-600">
<span className="justify-center">{fixture.away}</span>
...
and so on and it looks like this render of fixtures
When you click on one of these games it redirects to the /game page where I want to build add more stuff you can see about each game.
I want to know which game has been selected by the setFixture function which is called onClick of one of the games, and then I want to pass in the match variable to my new component (which is in a different .jsx file) so that I can render the game that has been selected on the new page.
I have tried to import the match variable from this file and the setFixture function in the new component file but cannot set my variables for the teams, date, venue etc. from this import and am just seeing many errors.
Can anyone help me with how this can be done? Recognizing which game has been selected and loading this into another file?
Thank you so much!
The usual approach to problems in React is to make use of Components. A component represents an object, and is provided a set of properties to allow that instance of the object to be represented.
So, even before going to your "next page" think about the Components that you could have on this "page" - each of the Fixtures you are representing can be a Component that takes properties that will help render the teams in that match. This will then lead to less repetition in each of your components - the Example() component will now render (for example) 6 Fixture() components.
Also, React is usually a Single Page Application. Whilst you're getting your basic application working you don't need to consider Routing just yet. Also, pages aren't "loaded"; components are re-rendered when Component properties ("props" for short) are updated. So, in the same page above you could have a Game() component that initially doesn't have any team props sent to it and behaves by not rendering until it has teams set.
You could use something like https://stackblitz.com/ to showcase what you have now, and it'd be easier to show how your code can be simplified.

How to render SVG component using props?

I'm trying to render an SVG using props of a function. Any help on how to achieve this?
Here is the code:
import React from "react";
import Camera from "../icons/Camera.svg";
export default function Button(props) {
console.log(props.icon);
return (
<button
type="button"
className="mx-auto mb-2.5 flex items-center gap-2 rounded-lg border border-gray-300 px-3.5 py-2 text-sm font-medium text-gray-700 drop-shadow-sm"
>
{props.icon} /* SVG ICONS GOES HERE*/
{props.label}
</button>
);
}
Could try:
import React from "react";
import Camera from "../icons/Camera.svg";
export default function Button({icon, label}) {
return (
<button
type="button"
className="mx-auto mb-2.5 flex items-center gap-2 rounded-lg border border-gray-300 px-3.5 py-2 text-sm font-medium text-gray-700 drop-shadow-sm"
>
{icon && <img src={Camera} alt={label} />}
</button>
);
}
Here is how you can add an Icon
https://codesandbox.io/s/react-playground-forked-x4vsge?file=/index.js
However, a few things when you are creating these components.
If the Icons source is an API (CMS) then you should have some predefined icons and should have your icons library build and pass just icon names.
If you have very limited icons build SVG icons as components and use them
When you use your Button component just use the SVG as a JSX
import Camera from "../icons/Camera.svg";
export default function App() {
return <Button icon={<Camera />} label="Click Me" />;
}

React: trigger onChange on checkbox input when changing checked state programmatically?

I have a ref to an <input type="checkbox"/> element, and when I programmatically set checked=false on the element, the element's onChange callback does not get called.
I tried using ref.dispatchEvent(new Event('input')) and ref.dispatchEvent(new Event('change')) and neither caused the React onChange callback to get executed.
All the questions and answers I could find on StackOverflow about this have to do with <input type="text"/> elements, none dealing with changing the checked property programmatically on an <input type="checkbox"/> element and its onChange handler not being invoked.
Here's a CodePen that demonstrates the issue:
https://codepen.io/dossy/pen/QWKVNzZ/left/?editors=0011
You can check and uncheck the checkbox, and the <div>Checked!</div> will appear and disappear as expected. However, clicking the <button>Reset</button> will uncheck the checkbox if it's checked, but since the input's onChange handler isn't being executed, the div isn't being hidden as it should be.
...
Yes, I know that I could do this as a Controlled Component but that's not the point: I have a use case where using refs is required so I must implement this as an Uncontrolled Component, and getting the onChange handler to execute when the DOM element changes is the problem I need to solve.
Thanks!
Here is the working code. working link https://codesandbox.io/s/blissful-wozniak-cc1sn?file=/src/Test.js:0-1753
import React, { useEffect, useRef } from "react";
export function Test() {
const ref_input = useRef(null);
const ref_text = useRef(null);
useEffect(() => {
ref_input.current.addEventListener("change", function (event) {
alert(event.target.checked);
});
}, []);
function triggerEvent(element, eventName) {
var event = document.createEvent("HTMLEvents");
event.initEvent(eventName, false, true);
element.dispatchEvent(event);
}
return (
<div className="h-screen flex bg-white text-gray-900 justify-center items-center">
<div className="flex items-start w-64">
<div className="flex items-center gap-4">
<button
className="inline-flex items-center px-4 py-2 border border-gray-500 rounded-md"
onClick={() => {
ref_input.current.checked = false;
triggerEvent(ref_input.current, "change");
//ref_input.dispatchEvent(new Event("input"));
//ref_input.current.dispatchEvent(new Event("onChange"));
}}
>
Reset
</button>
<div>Checkbox:</div>
<input
ref={ref_input}
type="checkbox"
className="h-4 w-4 border-gray-300 rounded"
// onChange={(e) => {
// console.log("onChange called", e.target.checked);
// e.target.checked
// ? ref_text.current.classList.remove("hidden")
// : ref_text.current.classList.add("hidden");
// }}
/>
<div ref={ref_text} className="hidden">
Checked!
</div>
</div>
</div>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
It's better to do things the "react way".
That means, instead of manipulating dom elements with imperative code (if you're using refs, you're using imperative code), do it declaratively with state/props:
function App() {
const [checked,setChecked] = React.useState(false);
return (
<div className="h-screen flex bg-white text-gray-900 justify-center items-center">
<div className="flex items-start w-64">
<div className="flex items-center gap-4">
<button
className="inline-flex items-center px-4 py-2 border border-gray-500 rounded-md"
onClick={() => setChecked(false)}
>
Reset
</button>
<div>Checkbox:</div>
<input
type="checkbox"
checked={checked}
onChange={() => setChecked(!checked)}
className="h-4 w-4 border-gray-300 rounded"
/>
<div className={checked ? '' : 'hidden'}>
Checked!
</div>
</div>
</div>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
Here's a link to the updated pen: https://codepen.io/zuze-lab/pen/QWKVEbY?editors=0011
EDIT: I want to be really clear, ref's aren't bad, not at all. Lots of react libraries expose refs because imperative code makes sense for those libraries APIs. When using refs to add event listeners, or imperatively manipulate elements, you're doing things wrong and you need to back up.

Categories