With React Starter Kit's Isomorphic CSS style loader for Webpack how'd I pass in the style object instead of the class name?
We can currently do this:
<div className={s.root}>...</div>
and I wonder if we can do something like this:
<FooBar style={s.root.toObject} />
I'm looking for a solution that also works when server-side rendered.
I assume, you want to convert a piece of CSS into inline style object? E.g. .comp { border: 1px solid red; } would become { comp: { borderWidth: 1px, borderStyle: 'solid', borderColor: 'red' }. For this task you may want to search for another NPM package (both css-loader and isomorphic-style-loader are intended to solve a different problem). Try Radium.
Related
I'm using css modules in a create-react-app project (React V17.0.2 / React-Scripts V4.0.3). All seems well in local but the styles break in production (hosted on netlify).
I believe the problem is that the css modules are not recognizing variables I've defined globally in plain css files. Here's an example of the set up I came up with:
index.css file imported at the top level index.js in my react project:
#import '../Global/ColorScheme.css';
body {
// body styles
}
a {
// global a tag styles
}
ColorScheme.css:
:root {
--green: #00b890;
--pink: #ef767a;
--brown: #554348;
--orange: #fb8f67;
}
Then some CSS module consuming global styles from ColorScheme.css..
SomeFile.module.css
.greenBox {
background-color: var(--green);
height: 500px;
width: 500px;
border: 1px solid #333;
}
Example Component
import React from 'react';
import styles from '../somePath/SomeFile.module.css';
export default function MyComponent() {
return <div className={styles.greenBox} />;
}
When I run it locally I will get a green box with height & width at 500px with a 1px solid black border around it. So all is working as expected. However the production build will show a 500px by 500px box with 1px solid black border but no background color. I'm guessing it's the disconnect is when a css module is using a variable defined in a plain css file. Maybe something with the way webpack compiles down a create-react-app for production build?
Does anyone have any ideas as to why this might be happening and any way I can get around it? I've seen instances of global variables in css modules but I'm trying to avoid importing the global styles in every single module.
I found the solution to my own problem and originally had that solution in the OP as an edit. Moving this to 'Answer my own question' so it's more clear if someone finds this issue in the future:
I found a work around by chance, but I don't understand the 'why' or 'how'. It seems like my custom CSS properties defined in :root were working, just not the ones I titled with color names (i.e. --navy, --green, --orange, or even --gray-scale-0). After running create-react-app's standard npm run build the produced main.css file would replace my css like this:
Some CSS Module Before Build
.someClass {
color: var(--green);
background-color: var(--gray-scale-0);
}
Same Class in Main.####.chunk.css After Build
.someClass {
color: var(green);
background-color: var(gray);
}
Changing my custom properties to something like --theme-orange or --theme-green works just fine. I'm still new to webpack and preprocessors so if anyone knows why this happens I'd love to know.
You should define the variable with $ and use it also with $ without any problem =>
$green : #00b890;
.greenBox {
background-color: $green;
}
I need to change background color for this css code
.mat-toolbar.mat-primary {
background
: #d12626;
color: #fff;
}
.mat-toolbar.mat-primary {
background: #d12626;
color: #fff;
}
I need to change the background for the above code. How to do that
I tried
[ngStyle]=' .mat-toolbar.mat-primary {
background: #d12626;
color: #fff;
}
'
But not working Then i got another suggestion from stackoverflow
[style.font-size]="fontSize+'px'" this code is working for 'font-size' but not woking for my need code this is my need [style.mat-toolbar.mat-primary.background]='#d12626'; but not working
I used this
.mat-toolbar.mat-primary {
background: #d12626;
color: #fff;
}
code inside CSS code and it is working but I need to change the color dynamically.
I also need to update his colors
primaryColor
primaryLightColor
primaryDarkColor
secondaryColor
secondaryLightColor
secondaryDarkColor
primaryTextColor
secondaryTextColor
dont set the material color as primary or secondary then you can use ngStyle like this
<mat-toolbar [ngStyle]="{background:bgColor , color:'#fff'}">
<mat-toolbar-row>
<span>Main Toolbar</span>
</mat-toolbar-row>
</mat-toolbar>
bgColor is just a component property, when you don't set the color property the component don't have any class so it 's easy to change the style
demo 🚀
Dynamic styles
You should make the CSS properties as camelcase, for the font-size should be like this [style.fontSize.px]. You check other solutions from how-to-apply-dynamic-styles?.
Override styles
We can do so using by combining the :host with the ::ng-deep selector and most probably using for overriding Material styles:
:host ::ng-deep h2 {
color: red;
}
Custom theme for Angular Material
You can change a set of colors that will be applied to the Angular Material components.
https://material.angular.io/guide/theming
Without hack, it's not possible to change on the fly the colors of you angular application because the way to style your application using Angular Material is to use theming (that is described here https://material.angular.io/guide/theming) and your theming scss files will be compiled to css at build time.
I think the only hack to change colors of your app on the fly is to identify the hex color that you want to change (for primary, secondary, etc...) and you rewrite your style tag in your document using serch / replace.
But keep in mind that Angular Material is not designed to let user change theme and colors because they provide palette and hue that have been designed to provide good contrast and best practice regarding UX. That's why the solution I give you is really a hack.
the matrial dynamic color will be possible if the main set by css variable instaid of static hex values ,someone already publish a library to solve this by overwrite the main color to be used by css variables.
1️⃣ install angular-material-css-vars library
npm i angular-material-css-vars -S
2️⃣ import MaterialCssVarsModule on app module
#NgModule({
imports: [
...
MaterialCssVarsModule.forRoot(),
],
...
})
export class AppModule {}
3️⃣ use this service 👉 MaterialCssVarsService to change angular material main color like primary ,secondary, warm...
export class component {
constructor(public materialCssVarsService: MaterialCssVarsService) {
const hex = "#3f51b5"; // set default color color
this.materialCssVarsService.setPrimaryColor(hex);
}
setPrimaryColor(color: string) {
this.materialCssVarsService.setPrimaryColor(color);
}
}
you need to remove any existing #import '~#angular/material/theming'; from your main stylesheet file.
👉 demo 🧙♂️
you may check this question create angular material theme with css variables for more help
How and where can one use ::ng-deep in Angular 4?
Actually I want to overwrite some of the CSS properties of the child components from the parent components. Moreover is it supported on IE11?
Usually /deep/ “shadow-piercing” combinator can be used to force a style down to child components. This selector had an alias >>> and now has another one called ::ng-deep.
since /deep/ combinator has been deprecated, it is recommended to use ::ng-deep
For example:
<div class="overview tab-pane" id="overview" role="tabpanel" [innerHTML]="project?.getContent( 'DETAILS')"></div>
and css
.overview {
::ng-deep {
p {
&:last-child {
margin-bottom: 0;
}
}
}
}
it will be applied to child components
I would emphasize the importance of limiting the ::ng-deep to only children of a component by requiring the parent to be an encapsulated css class.
For this to work it's important to use the ::ng-deep after the parent, not before otherwise it would apply to all the classes with the same name the moment the component is loaded.
Using the :host keyword before ::ng-deep will handle this automatically:
:host ::ng-deep .mat-checkbox-layout
Alternatively you can achieve the same behavior by adding a component scoped CSS class before the ::ng-deep keyword:
.my-component ::ng-deep .mat-checkbox-layout {
background-color: aqua;
}
Component template:
<h1 class="my-component">
<mat-checkbox ....></mat-checkbox>
</h1>
Resulting (Angular generated) css will then include the uniquely generated name and apply only to its own component instance:
.my-component[_ngcontent-c1] .mat-checkbox-layout {
background-color: aqua;
}
USAGE
::ng-deep, >>> and /deep/ disable view encapsulation for specific CSS rules, in other words, it gives you access to DOM elements, which are not in your component's HTML. For example, if you're using Angular Material (or any other third-party library like this), some generated elements are outside of your component's area (such as dialog) and you can't access those elements directly or using a regular CSS way. If you want to change the styles of those elements, you can use one of those three things, for example:
::ng-deep .mat-dialog {
/* styles here */
}
For now Angular team recommends making "deep" manipulations only with EMULATED view encapsulation.
DEPRECATION
"deep" manipulations are actually deprecated too, BUT it's still working for now, because Angular does pre-processing support (don't rush to refuse ::ng-deep today, take a look at deprecation practices first).
Anyway, before following this way, I recommend you to take a look at disabling view encapsulation approach (which is not ideal too, it allows your styles to leak into other components), but in some cases, it's a better way. If you decided to disable view encapsulation, it's strongly recommended to use specific classes to avoid CSS rules intersection, and finally, avoid a mess in your stylesheets. It's really easy to disable right in the component's .ts file:
#Component({
selector: '',
template: '',
styles: [''],
encapsulation: ViewEncapsulation.None // Use to disable CSS Encapsulation for this component
})
You can find more info about the view encapsulation in this article.
Make sure not to miss the explanation of :host-context which is directly above ::ng-deep in the angular guide : https://angular.io/guide/component-styles. I missed it up until now and wish I'd seen it sooner.
::ng-deep is often necessary when you didn't write the component and don't have access to its source, but :host-context can be a very useful option when you do.
For example I have a black <h1> header inside a component I designed, and I want the ability to change it to white when it's displayed on a dark themed background.
If I didn't have access to the source I may have to do this in the css for the parent:
.theme-dark widget-box ::ng-deep h1 { color: white; }
But instead with :host-context you can do this inside the component.
h1
{
color: black; // default color
:host-context(.theme-dark) &
{
color: white; // color for dark-theme
}
// OR set an attribute 'outside' with [attr.theme]="'dark'"
:host-context([theme='dark']) &
{
color: white; // color for dark-theme
}
}
This will look anywhere in the component chain for .theme-dark and apply the css to the h1 if found. This is a good alternative to relying too much on ::ng-deep which while often necessary is somewhat of an anti-pattern.
In this case the & is replaced by the h1 (that's how sass/scss works) so you can define your 'normal' and themed/alternative css right next to each other which is very handy.
Be careful to get the correct number of :. For ::ng-deep there are two and for :host-context only one.
Just an update:
You should use ::ng-deep instead of /deep/ which seems to be deprecated.
Per documentation:
The shadow-piercing descendant combinator is deprecated and support is
being removed from major browsers and tools. As such we plan to drop
support in Angular (for all 3 of /deep/, >>> and ::ng-deep). Until
then ::ng-deep should be preferred for a broader compatibility with
the tools.
You can find it here
I looked through all those answers and found nobody mentioned a child component can pass a style CSS in from its parent.
In component ts file, you can use this:
#Input() styles: any = {};
In component html file, you use this:
[ngStyle]="styles"
in parent, you use this :
<yourComponent [styles]="{backgroundColor: 'blue', 'font-size': '16px'}">
Please see more details here: Best way to pass styling to a component
In this way, we didn't break encapsulation, which is one of those most important Object orientation principles
Use ::ng-deep with caution. I used it throughout my app to set the material design toolbar color to different colors throughout my app only to find that when the app was in testing the toolbar colors step on each other. Come to find out it is because these styles becomes global, see this article Here is a working code solution that doesn't bleed into other components.
<mat-toolbar #subbar>
...
</mat-toolbar>
export class BypartSubBarComponent implements AfterViewInit {
#ViewChild('subbar', { static: false }) subbar: MatToolbar;
constructor(
private renderer: Renderer2) { }
ngAfterViewInit() {
this.renderer.setStyle(
this.subbar._elementRef.nativeElement, 'backgroundColor', 'red');
}
}
I have understood the concept of CSS modules so much that I am convinced that I do not want to do anything else that that for the future.
Currently I am trying to refactor an existing app to use CSS modules, the app has used classic sass with BEM methodology since.
Before I describe my problem I want to make clear that I undestand that I am addressing an issue that is not really within the domain of CSS modules. One should apply styles solely for usage inside a single module. At the most one should compose CSS classes with other CSS classes of other modules. But basically: You build an (HTML-)module and you use CSS modules to style that module and that's that.
Here's the problem:
In the process of refactoring there is one single issue that derives from having had a SASS-based style system. I can't find a valid method to work with a CSS class within a CSS modules environment when this class should work in combination of another class from another module.
Example in SASS:
[page.scss]
.wrapper {
margin: 0;
}
[headline.scss]
.headline {
color: green;
}
.wrapper {
.headline {
color: orange;
}
}
As you can see: One module (page) defines a CSS class "wrapper", another module defines a CSS class "headline". And, additionally, the class "headline" should behave a bit differently when placed inside the class "wrapper".
Again, I know that this is not really the domain of CSS modules. But I really would like to know if this is somehow doable with CSS modules? The "composes"-feature of CSS modules does not really fit here...
This is a common issue when migrating to CSS Modules. In short, a css module cannot override a style from another css module, and this is by design. Styles are supposed to live with the components that render them, and nowhere else.
What you can do to refactor this is to create a component style variant and explicitly set the variant through a prop when rendered within your wrapper.
For example, suppose your headline component currently looks something like this:
CSS
.headline {
color: green;
}
JSX
import styles from "Headline.css";
const Headline = () => {
return (
<div className={styles.headline} />
);
}
Rather than trying to override the .headline class name from somewhere else, you can create a variant class name that you toggle through a prop:
CSS
.headline-green {
color: green;
}
.headline-orange {
color: orange;
}
JSX
import styles from "Headline.css";
const Headline = ({orange}) => {
return (
<div className={orange ? styles.headlineOrange : styles.headlineGreen} />
);
}
And when you render it from your wrapper, set it to the orange variant:
<Headline orange />
Tip: you can use composes to eliminate duplicate common styles between your variants.
I am setting up a project with React JS and want to use auth0 to handle authentication (and maybe some serverless functions).
auth0 provides a nice "seed" project https://github.com/auth0-samples/auth0-react-sample that works basically out of the box.
The code for the main container uses JSX and loads css style from a module file. The module file provides the className classes that are used for styling.
I am extending the bootstrap layout with React-Bootstrap components, and am able to style some components using classNames syntax.
For example, I am styling a Navbar's background color like this:
Appending to the css module file /01-Login/src/views/Main/styles.module.css
.mainNavBar{
background-color: rgb(45, 140, 210);
border-color: rgb(45, 140, 210);
}
Then to the file containing JSX 01-Login/src/views/Main/Container.js
<Navbar className={styles.mainNavBar} fixedTop>
...
</Navbar>
However, when I try to style other inner elements, ie the text color,
I tried:
.mainMenuItem {
color: #fff;
}
And:
<NavItem className={styles.mainMenuItem} eventKey={1} href="#">Link</NavItem>
It doesn't work. I think it is because I don't know how to reach the children of NavItem.
I tried this and variations of it:
.mainMenuItem ul > li > a {
color: #fff;
}
But it just doesn't seem to be the right way to do it, and doesn't work ( though an 'li' item got styled with the color at some point when inspected on the browser, but not the 'a' ...).
Finally, I tried inline styles (see related question Add inline style in reactjs without using JSX) but this seems to suffer from the same inheritance problem.
Thanks so much if you can point me in the right direction as I am confused.
Edit 19/07/2016
Looks like NavItem doesn't get the style elements...
I submitted an issue to react-bootstrap:
https://github.com/react-bootstrap/react-bootstrap/issues/2070
I used inline styles with javascript syntax with Radium instead of passing standard css with the "Classname" attribute.