First dynamically added component not getting styling from a class - html

I have a big list of dynamically added components and all of them are getting styling from the css class except the first one. It's specifically a darkmode or litemode class that gets added depending on the if this.state.dark === true or not
here's the function that renders them
renderComponent(info) {
return <Info isDark={this.isDark()} isHidden={this.state.hide === true} user={info} key={info} />
}
and this is what calls that function
{info.map(this.renderComponent)}
css class that's not rendering on first component
.darkmode + .other-class {
background-color: rgb(131, 21, 21);
}
I've tried conditionally rendering the page into a separate version with just darkmode and using the classes directly everywhere(ie there's no way they don't have the class).
In inspect element it says they have the class and even styling from a different area in the css is being applied. but the background stays transparent on just the first element.
I've also tried adding the class in the component itself and it's always the exact same result.
https://i.imgur.com/vLa8Tn9.png picture of the element not loading the css
https://i.imgur.com/cJxT5bU.png picture of element that is loading the css

I think this is a problem with your CSS selector.
The plus (+) sign select and style every element that is placed inmediately after the first element in your CSS selector.
In W3School you can see this behaviour
I think what you are trying to do is this:
.darkmode.Offline {
background-color: rgb(131, 21, 21);
}

Related

Can you set body id dynamically in React?

I am trying to implement dark mode in my app.
The idea is to add this to the root element:
<div id="dark">
And then this in CSS:
#dark {
background-color: #1A1A2E;
}
And then in Css, customize each dom element by using classes. For example, here I will work on cards:
#dark .card-body {
background-color: #16213E !important;;
}
#dark .card-header {
background-color: #0F3460 !important;
}
Now, this works perfectly fine.
But, with Modals, it does not work. I think it's because Modals are not rendered initially so for some reason the dark style does not apply to them.
What worked though is adding id="dark" to each modal:
#dark .modal-header {
background-color: #0F3460 !important;
}
#dark .modal-body {
background-color: #16213E !important;;
}
#dark .modal-footer {
background-color: #16213E !important;;
}
<Modal
// dark doesn't get applied automatically for modals because apparently modals are not rendered in the beginning
id="dark"
isOpen={this.state.isModalOpen}
toggle={this.toggleModal}
>
<div className="modal-header">
But, it'll be a pain to apply this to every single modal.
One solution mentioned here:
Modal should be the descendant of a tag which has id="dark". It is
loaded by the script right below the script tag and you are trying to
put 'dark' id on some div tag and the modal doesn't lie inside it,
thus the CSS selector not targeting it.
So, you need to put id="dark" on the body tag.
This solves the modals issue.
But, the problem is in my original implementation of dark mode, I am controlling that id in the root component like this:
// Root component
<div id={this.state.should_enable_dark_mode ? "dark" : "default"}>
And should_enable_dark_mode is managed like this:
manageDarkMode() {
window.addEventListener("storage", () => {
console.log("change to local storage!");
let should_enable_dark_mode = localStorage.darkMode == "true";
this.setState({
should_enable_dark_mode,
});
});
}
So the problem with the solution mentioned above is that I couldn't find a way to control the body tag from the react app. And I am not sure if it's a good thing to do.
What do you think I should do?
I see in the comments to your original question that you decided to just modify the body element in the browser DOM, which will probably work fine since the body element is not controlled by React and will likely not be changed by any other code.
I would however like to suggest a few improvements that makes it at bit less dirty:
use a data attribute like data-display-mode="dark" as a target for your CSS selectors instead of the ID. IDs are supposed to be stable and other tools and libraries (e.g. UI test tools) might rely on this.
use the Modal.container property to attach your Modals to the App element (the React-controlled global parent div defined in your React code, which you can control, not the app-root-div in index.html). Then set your data-display-mode attribute here by React-means. This way you will not bypass the virtual DOM.
use CSS custom properties for defining your colors, and then define all dark mode modifications in one place. Don't spread your dark-mode-styling code across multiple class selectors - you will have a hard time maintaining this.

How to make CSS style final?

I need help on how to make CSS styles final so that they could not be overwritten by Javascript.
Problem: Sometimes, because of the img tag in the JavaScript code, everything, (all styles of all of the images) gets overwritten.
Here is my code:
<img src='logoImg' style='width:45px; height:30px;' >
Please tell me ways to do this in JavaScript or in CSS itself.
Desired output: I need the Logo Image to have final styling. So it is not affected by JavaScript through the DOM (document object model).
You can try adding !important keyword to your CSS properties to prevent them from getting changed.
Example
const test = document.getElementById("test");
// The color won't change to orange
// due to !important keyword in the CSS code
test.style.backgroundColor = "orange";
#test {
width: 50px;
height: 50px;
background: green !important;
}
<div id="test"></div>
Ideally though it would be better to work around this using a different solution like using a more specific method of selecting an HTML element and changing it's properties.
If you have some kind of a style applied by selecting a tag, you can override it by using a class or an id when it comes to CSS. If you're searching for elements in JavaScript code, you can look for them by a class name or an id value instead.
An alternative solution in your case would be to re-write/modify the JavaScript code that targets your img tags and either skip images that have a specific class like let's say logo, or make a custom class for all your standard images that do not include your logo element and look them up in your JavaScript code using document.getElementsByClassName method.
If you want to prevent JS to overwrite the style of an image, you need to style it in CSS and add important; to raise it specificty weight. !important has a higher specificty weight then inline-style and as such JS style (JS add the style as inline-style) wont apply.
function resize() {
document.querySelector("img").style.height = "200px";
document.querySelector("img").style.width = "200px";
}
img.test {
width: 45px !important;
height: 30px !important;
}
<img src='https://via.placeholder.com/200x200.jpg' class="test">
<button onclick="resize()">Test</button>

StencilJS - Why do some styles (e.g., background-color) apply to all elements when styling container?

I'm using Stencil JS to write components for a micro front-end I'm building. I have a <dashboard-container> that as the name suggests, holds all the other components I have.
I'm trying to change the background color of my index.html's body and then let every other element, component keep their own style.
The problem is that if I try to apply background-color: red to my <dashboard-container>, the rest of the children also inherit the background color.
I'm expecting that if I apply a background color to a parent element, the children keep their own styles but it's not working that way.
How can I style a component without the children inheriting it?
This is how I have it set up:
import { Component, h } from '#stencil/core';
#Component({
tag: 'lh-dashboards-container',
styleUrl: 'lh-dashboards-container.scss',
scoped:true
})
export class LhDashboardsContainer {
render() {
return (
<div class="lh-dashboards-container">
<lh-dashboards-navigation></lh-dashboards-navigation>
<lh-dashboards-cohort-finder></lh-dashboards-cohort-finder>
</div>
);
}
}
So, if I do the following:
//lh-dashboards-container.scss
.lh-dashboards-container {
background-color:red;
}
Every child component and their element within will have their background changed to red.
You can add all: initial; on the child elements but it will specify that all the element's properties should be changed to their initial values.
It's better to style the children, to override the ones being inherited from parent, if needed.
You can read more about all here.

host + ng-deep + body css not applied

I'm trying to make a background color for a specific component being display in the whole component page.
It's working fine with
\ ::ng-deep body
background-color: red
But the things is when i do it like that, the body css is bleeding to the other component page, which become red too.
So what i really want to do, is making it local with host.
I tried to use
\:host ::ng-deep body
But it wasn't working too, the body background did not change color until i add a specific body tag to my html file component.
But i don't want to add a body tag because when i do this, the body size is limited to the element in the page.
I also try to use ViewEncapsulation, but it messed up with all my css.
Any help would be appreciate.
Your first issue (As you found out) with ng-deep is that it bleeds into other pages. And because CSS is lazy loaded inside Angular, everything will be fine until you go to that page, and then head to another page and suddenly everything will be red.
Your second issue is that the :host pseudo selector isn't saying "For this page only" it's saying "For everything inside this component".
So as an example :
If I have a component called MyComponent, and I have css like :
:host ng-deep div {
background-color :red;
}
And I have a template like so :
<body>
<app-mycomponent>
<div></div>
</app-mycomponent>
<app-secondcomponent>
<div></div>
</app-secondcomponent>
</body>
Only the div inside app-mycomponent would be red. The div inside app-secondcomponent would not be read. Again, :host allows you to ng-deep only within that component.
So why would you need this? Generally it's because you may use a library that you want to style, so you can place it inside a wrapper component and use ng-deep commands freely with the :host prefix, so only the library component inside that wrapper is styled and the rest of your application is unaffected.
So what's the solution? Well the other issue you have is that the <body> tag is actually outside the scope of your angular app. Typically when I've had to edit the body/html tags as a whole, I've just used plain old javascript.
So for example :
export class AppComponent implements OnInit, OnDestroy {
ngOnDestroy(): void {
document.body.style.backgroundColor = 'transparent';
}
ngOnInit(): void {
document.body.style.backgroundColor = 'red';
}
}
It's not the nicest thing in the world, but it's also not terrible. I mostly have to do this when creating modal components that want to stop the body scrolling etc.
For more reading on NG-Deep bleeding : https://tutorialsforangular.com/2020/04/13/the-dangers-of-ng-deep-bleeding/
And how :host works : https://tutorialsforangular.com/2019/12/24/using-the-css-pseudo-element-host-in-angular/

CSS styles get applied without class declaration

Now, this is a new one ... I have a class declaration in SCSS:
.video {
a {
// some stuff
}
}
There are the classes: wrap - container - row - content and then some html:
<div class="btn-large">
View more
</div>
This 'a' has the styles from '.video a' applied, but in the whole source, there's no mention of 'video'. I checked the compiled css and it's '.video a'. The rule also shows up as applied in Safari (and Chrome, and Firefox). How's that possible?
There is no way for the styles to be applied if the selector doesn't match.
You have ruled out the class appearing in the source.
Therefore, it is being added to some element using JavaScript.