Tailwind custom pseudo element - javascript

I'm trying to create a single js file for a component that is used with several styles in my project.
On one page I have several buttons for some features, with a default background color set in the html file (for exemple bg-gray-500).
For buttons where the feature is activated I change the background color, currently with js, but therefore the bg color for the "activated feature" (for exemple bg-blue-500) is defined in the js and this is what I would like to move to the html file.
So, instead of having <button type="button" class="bg-gray-500"></button> and having the js removing the class bg-gray-500 and adding the class bg-blue-500, I wonder if this is possible to have something like <button type="button" class="bg-gray-500 selected:bg-blue-500"></button> where the js would only have to add or remove the class selected to switch between the one and the other color, instead specifing the color itself.
Thank you

You may write simple plugin for custom variants
// tailwing.config.js
const plugin = require('tailwindcss/plugin')
module.exports = {
theme: {
extend: {},
},
plugins: [
plugin(function({ addVariant }) {
addVariant('selected', '&.selected');
addVariant('parent-selected', '.selected &');
})
],
}
HTML
<div>
<button class="bg-blue-500 selected:bg-red-500 selected">
Button
</button>
</div>
<div class="selected">
<button class="bg-blue-500 parent-selected:bg-yellow-500">
Button
</button>
</div>
The magic here is addVariant() function where the first parameter is variant name (could be any but must be unique among all variants - in HTML use it like selected:), second - CSS selector (so &.selected means element with class .selected) or callback function which should return string as CSS selector
In a demo I created two cases just for example - toggle class on element itself or parent element
DEMO - toggle selected class to see effect

Related

Why is my decoration-${some_color} class not working correctly?

I have been trying to change the underline color decoration of some text according to a specific value given to a React component via this method:
<span className={`underline underline-offset-4 decoration-4 decoration-${decorationColor ? decorationColor : 'primary'}`}> {sentence.text}</span>
However, it is not working correctly. When I inspect the HTML file it has indeed the color I wrote, for instance: decoration-secondary. Nevertheless, the text doesn't appear to be changing accordingly.
If I write directly 'decoration-secondary' instead of passing 'secondary' within the props and then using decoration-${decorationColor ? decorationColor : 'primary'}, it suddenly works.
I found out that this only happens whenever I had not previously directly written the class name within the file. For example: I have used 'bg-primary', 'bg-secondary', and several times in other parts of the app, and thus, when using `bg-${decorationColor ? decorationColor : 'primary'}' it just works perfectly.
TailwindCSS doesn't allow you to generate classes dynamically. So when you use the following to generate the class…
`underline underline-offset-4 decoration-4 decoration-${decorationColor ? decorationColor : 'primary'}
…TailwindCSS will not pick that up as a valid TailwindCSS class and therefore will not produce the necessary CSS.
Instead, you must include the full name of the class in your source code. You can return the full value like this
function myDecoStyle(decorationColor) {
if(decorationColor)
return "underline underline-offset-4 decoration-4 decoration-"+decorationColor;
else
return "underline underline-offset-4 decoration-4 decoration-primary";
}
where decorationColor is your colour value you are passing here.
By doing it this way, the entire string for every class is in your source code, so TailwindCSS will know to generate the applicable CSS.
And use it like
<span className={`${myDecoStyle(secondary)}`}> {sentence.text}</span>
Read more: https://tailwindcss.com/docs/content-configuration#class-detection-in-depth

How do I add style to a react element within the return function?

I'm trying to add style to an element in my return of a react component, but I want to achieve this without adding a class. My text editor auto fills a style option, but I believe the syntax is wrong, since when trying to add a function on an onClick event, its a little different when its in the return of a react element. For example, instead of
onClick=function()
its
onClick={() => {function()}}
I'm hoping that instead of style={"background-color: green;"} its a different syntax to actually allow style changes once it hits the dom.
In-line styles can be done, and here is a code example as you have not provided one.
for example, lets inline style an h1 tag
<h1 style={{background-color:'green', color:'white'}}>This is a tilte</h1>
more can be found here
additionally, I would not recommend inline styling as it's not industry-standard and can cause your code to become bloted.
Style tags in react can indeed contain a references to functions.
I am not fully sure if you are working with React component classes or component functions, but your syntax can besides as follows. Create a variable called customStyle which will contain a function that returns your required style object:
customStyle = () => { return { color: 'red' } };
You can then reference customStyle inside markup as follows:
<div style={this.customStyle()}>My Element</div>
idont know if i understood your question well, You can achieve what you want by making a style state, then mutate it whatever style you want with setState
const [style, setStyle] = useState({})
const App = () => {
return <div style={style}>
<button onClick={() => setStyle({color: 'red'})}>handler button </button>
</div>
}

Animate.css add animation on click

I want to animate an image input when the user click the image, I'm using animate.css with Bootstrap and Angular, I've seen some examples to add the animate class when the image is click but nothing happens, when I console.log the element in the function I can see that the animate class is added but didnt work, also I got an error message in the console.
html code
<input type="image" src="../../../assets/img/as-logo-150dpi-05.png" class="d-block animate__animated animate__slideInLeft" id="offMenu" (click)="animateLogo()">
TS code
animateLogo(){
const element = document.querySelector('#offMenu');
if(element) {
element.classList.add('animate__animated', 'animate__bounceOutRight');
console.log(element)
}
}
As you can see in the input class, the aniimate class "animate__bounceOutRight" is added but nothing happens in my project, any advice on this?
So after the answer I found out the error message is because of bootstrap, nothing to do with the animation, and the problem was because the input already have an animation, when the function added another this overlaps and didint make it work so I need to disable the first one to make the second works but now the input disappear because of the second animation
HTML
<input type="image" src="../../../assets/img/as-logo-150dpi-05.png" class="d-block animate__animated animate__slideInLeft" id="offMenu" [ngClass]="{'animate__slideInLeft ': firstAnimation , 'animate__bounceOutRight': secondAnimation }" (click)="animateLogo()">
TS
firstAnimation: boolean; //This is true
secondAnimation: boolean; //This is false
animateLogo(){
this.firstAnimation = false
this.secondAnimation = true
}
Did you add the animate.css styles in your
angular.json
"styles": [
"node_modules/animate.css/animate.css"
],
OR
styles.css:
#import '~animate.css/animate.min'
Also just for a better approach let's try to do tackle your problem the Angular way
In your .ts create a boolean field named activateAnimation and we'll set it as true when the user clicks the image so your .ts code will look something like this:
activateAnimation: boolean;
animateLogo(): void {
this.activateAnimation = true
}
and then in your HTML we can conditionally add the animate.css classes that you want to add using the [ngClass] directive of Angular.
<input type="image" src="../../../assets/img/as-logo-150dpi-05.png"
class="d-block animate__animated animate__slideInLeft"
[ngClass]="{'animate__animated ': activateAnimation , 'animate__bounceOutRight': activateAnimation }" id="offMenu"
(click)="animateLogo()">```
Ok so after a little research I found a video that explains how to use Animate.css using jQuery and using the function that he explains with the click event I managed to take out the first animation class, add the second one and once the animations ends, take out the second animation class and add again the first animation class, all of this in the TS file, have some problems coding the jQuery in the TS file but the framework helps me out with the correct form of the code
So first in my <input> I added the class offMenu to identify my input, also I leave the animate__animated so I dont have to add it every time I take out or add an animation class and also I leave the animate__slideInLeft because I want to animate the input the first time ther page loads.
<input type="image" src="../../../assets/img/as-logo-150dpi-05.png" class="d-block animate__animated animate__slideInLeft offMenu" id="offMenu">
Next in my TS file in the constructor part I code the jQuery function, I create 3 variables:
The first one is effects this variable saves the second effect that
is animate__bounceOutRight.
The second variable is effectsEnd that saves the different classes
that Animate.css have to detect when the animation ends for the
different browsers.
And the third one is to save the element I want to add or remove
classes, in this case is my input with the class offMenu.
If you want to add one more variable to save the animate class you currently have, you can do it.
Next I select the element I want to add and remove classes and call the event on click once again in the function I select the element and remove the firts animate class 'animate__slideInLeft' as this animation already end theres no need to add the effectsEnd variable, next I add the second animation class that is saved in my variable effects, then with one we indicate this is going to happen one time and check fot the animation to end with the variable effectsEnd once the animation ends, we remove the animation class effects and add the firt animation class.
constructor() {
$(() =>{
var effects = 'animate__bounceOutRight';
var effectsEnd = 'animationend oAnimationEnd mozAnimationEnd webkitAnimationEnd';
var element = $('input.offMenu');
$(element).on("click", () => {
$(element).removeClass('animate__slideInLeft').addClass(effects).one(effectsEnd, () =>{
$(element).removeClass(effects).addClass('animate__slideInLeft')
});
});
})
}
Whit this code you can put one animation to show when the page is load and then add another animation when you click in the element and take back the element once the out animation is done, hope this helps someone else.

Change Multiple CSS property from multiple CSS class dynamically in Angular

In angular, we can easily change the property of a CSS class dynamically, like if I have a class
.my-class {
background: url('..')
}
and if I used my-class as
<div class="my-class">
------
</div>
now, we can change the image effectively by using
[style.background]="url(..)"
like
<div class="my-class" [style.background]="getImageUrl()">
----
</div>
Now, can anyone tell me, is there any solutions if there's have multiple css-class and there I have to change background url all of them, how can I do it?
Like my CSS classes are
.my-class-one {
background: url('..')
}
.my-class-two {
background: url('..')
}
.my-class-three {
background: url('..')
}
and HTML code is
<div class="my-class-one my-class-two my-class-three">
----
</div>
There I need to change all background image URL by calling angular methods
getImageUrlOne()
getImageUrlTwo()
getImageUrlThree()
ngClass can be used in html
[ngClass]="{'my-class-one': getImageUrlOne(), 'my-class-two': false, 'my-class-three': false}"
JS
getImageUrlOne(){
//.... logic to decide my-class-one should be used or not
return true;
}
You can set different-different flag variable in each function and when function call then set one flag true. set ngclass as below:
<div [ngClass]="{'my-class-one': getImageUrlOne(), 'my-class-two': getImageUrlTwo(), 'my-class-three': getImageUrlThree()}">

Find and change materialize generated html elements from react component

In a couple of places of my app, I have some code I am not very proud of. I need to find some elements that are handled by materialize to manipulate them, so that they are displayed according to my needs.
So I do this two things in two different parts of my code:
// 1.- set style from grey (placeholder text) to black(input text) and erase placeholder only on 1rst option select
const dropdownWrapper = document.getElementsByClassName('select-dropdown dropdown-trigger')[0];
dropdownWrapper.setAttribute("style", "color:black;");
// 2.- remove AM PM labels from display
let ampmLabels = document.getElementsByClassName('timepicker-span-am-pm')[0];
ampmLabels.setAttribute("style", "display:none;");
I don't consider useRef because the elements are not part of any specific component. They are in the DOM put there by materialize when I initialize the materialize element in my component and I manipulate them from that component to fit my needs when they're displayed.
As I know there are no more elements of this type when I run de code, the document.getElementsByClassName('select-dropdown dropdown-trigger')[0]; works, but isn't there a more elegant way to find a manipulate dom elements to do this?
Edit:
The componenet where the color cannot be changed is an input type with a type="text" attribute:
html with dropdownWrapper.classList.add('text-black');:
<input class="select-dropdown dropdown-trigger text-black" type="text" readonly="true" data-target="select-options-ee9a6017-aef6-ecbf-c2a1-298693b77804">
html with dropdownWrapper.setAttribute("style", "color:black;");:
<input class="select-dropdown dropdown-trigger" type="text" readonly="true" data-target="select-options-ee9a6017-aef6-ecbf-c2a1-298693b77804" style="color: black;">
Seems that because of that the dropdownWrapper.classList.add('text-black'); does not work. This adds the text black to the class name in the class="select-dropdown dropdown-trigger text-black" (note the text-black at the end) but does not change the text color even if the .text-black {color: black} is added to the css file.
The style change with setAttribute, produces the style="color: black;" at the end of the html that is what seems what is actually changing the color.
You can do something like this:
function addClass(selector, className) {
const element = document.querySelector(selector);
element.classList.add(className);
}
/* maybe move these strings to constants, add comments*/
addClass('.select-dropdown.dropdown-trigger', 'text-black');
addClass('.timepicker-span-am-pm', 'hidden');
Tiny improvements:
You can use document.querySelector()
You can also add the styles in a CSS class and use classList API:
Long version:
const dropdownWrapper = document.querySelector('.select-dropdown.dropdown-trigger');
dropdownWrapper.classList.add('text-black');
const ampmLabels = document.querySelector('.timepicker-span-am-pm');
ampmLabels.classList.add('hidden');

Categories

Resources