can I "import" React CSS modules from a string? - javascript

I have a React project that uses CSS Modules by importing .css files. e.g. import styles from "./styles/MyComponent.css";
I find myself now in a situation where a component is receiving a customized snippet of CSS as a string in response to a dynamic call to the server.
Is it possible to take this string (which is unknown until runtime) and essentially do the same thing to it that import does to the .css file when it is compiled by webpack?
For example:
import styles from "./styles/MyComponent.css";
//later on in component...
moreStyle = "a string containing valid CSS";
//do *something* here to moreStyle string to do whatever importing does to a file.
myJSX = (
<div className={styles.someClass}>
This div content is styled by someClass
</div>
<div className={moreStyle.someOtherClass}>
This div content needs to be styled by someOtherClass, but obviously this isn't working
</div>
);

You can try this:
import styles from "./styles/MyComponent.js";
myJSX = (
<div style={styles.someClass}>
This div content is styled by someClass
</div>
<div style={styles.someOtherClass}>
This div content needs to be styled by someOtherClass, but obviously this isn't working
</div>
);
Consider creating a serialized object, instead.
// Filename: MyComponentStyle.js
//Example styles
export const styles = {
someClass: { height: 10 },
someOtherClass: {
backgroundColor: 'red',
}
};
React doesn't work like your typical HTML/CSS/JS app. The thing to note that JSX may look like HTML but it is not HTML.
In your code, className is being defined as a string, which is expected, however, there's possibly no CSS being referred to in this document. Try to console.log it and see what you get.
...
Another possible solution is to simply have your style within the same component file. A common design choice for component styling is inline styling. This is especially useful for projects of medium-large scale, where managing files can get difficult.
Helpful references:
https://reactjs.org/docs/dom-elements.html#style
https://codeburst.io/4-four-ways-to-style-react-components-ac6f323da822

Related

Recreating HTML/CSS Behavior with Styled-Components

I have a fairly annoying problem using Styled-Components in a React app. The class names of the HTML elements are very important, as is the dynamism of styled-components (via props passing). So it's important that both are used.
tl;dr I want to use a classname in CSS (and not HTML) without having to create an empty component or something.
I have a class with a dynamic classname, let's stay "style-123", where "123" is dynamically changed via state and is important for parity with the current setup. (IMO, the dynamic nature of the classname is preventing a solution.) The "style-123" classname is used in other HTML elements, but it is not a component itself so should not show up as an HTML element.
I have a component ("ComponentA") that has a classname of "component-a". This component's HTML should looking like the following:
<div class="component-a">
HELLO
</div>
and its Styles (in Dev Tools) should look like this:
.style-123 .component-a {
margin-left: -2%;
}
where we now see the class ("style-123") added. This should be the final result.
The general structure of the HTML is along the lines of:
<div class="name-whatever style-123 another-classname">
<div>
<div class="component-a">
</div>
</div>
</div>
Problem
I do not seem to be able to isolate "component-a" as an HTML classname for "ComponentA" while applying CSS as .style-123 .component-a via styled-components. In order for the HTML to have an isolated classname, the component (JSX) would need to be:
<ComponentA className={'component-a'}/>
and the styled component:
const ComponentA = styled.div`
&.component-a {
color: red;
}
`
This is the only way I know how to link-up a component in JSX with its styled-component counterpart.
I cannot do:
<ComponentA className={'component-a'}/>
and the styled component:
const ComponentA = styled.div`
&.style-123 .component-a {
color: red;
}
`
as this won't apply the styling since there's a classname-mismatch.
I've tried many combinations of SASS, all the ampersands and arrows and pluses and etc., over the last few hours. I hope this is feasible via styled-components as I need to declare classnames and have classnames dynamic as well as the CSS attributes and values, all passed via props. If there is another solution that doesn't use styled-components but maintains this dynamism, I am open to that.
Thanks for the time.

How can I use style tag in JSX

So I'm in a situation where I have to use <style> tag, That is because I have multiple pages (I'm using react router DOM) so I cant apply the same style to every page as that would mess things up. Is there a way I can use <style> tag in JSX?
I have to use style tag like this:
function RandomScreen(){
return (
<div>
<style></style>
</div>
)
}
You can simply import a stylesheet into your page:
import './main.css'
Another solution is to use Emotion and the Global component:
https://emotion.sh/docs/globals
Can you use separate css file for every component and import every css file in every component you need.
import './RandomScreen.css';

How to use media print within Reactjs web app

I would like to hide a div when print preview happens but I find it almost impossible to do it in a React.
<div className="contacts"></div>
Is there any possibilities that I can add pure css or if React Stylesheet supports #media print and hide element with class name contacts when print preview.
I was reading this article https://blog.logrocket.com/the-best-react-inline-style-libraries-comparing-radium-aphrodite-emotion-849ef148c473 but it just seems too much work for something that I would do poorly in css within a matter of seconds.
Any idea how can I achieve such thing in Reactjs?
Inline media queries are not possible. The closest you can get is inlining a stylesheet, like so (in React syntax):
<div className="contacts">
<style>
{`#media print {.contacts{display: none;}}`}
</style>
</div>
A bit old but maybe it will be useful for someone. If you want to use React styles you can also do:
const useStyles = makeStyles((theme: Theme) =>
createStyles({
contacts:{
display: "block",
},
[`#media print`]: {
contacts:{
display: "none",
},
}
}))
...
const classes = useStyles();
...
<div className={classes.contacts}></div>
This markup works for me with FunctionComponents flawlesly.
You cannot use media queries (also pseudo-classes and pseudo-selectors) inside inline styles. You need to extract your css into a sepparate .css file and to import it either inside your component's file (if you use bundlers like webpack) or just include it inside your html with <link> tag

Duplicated styles on head and a lot of <style> elements

I'm quite happy with angular-material2 components but there are some weird behaviors that I don't understand and they don't have a proper documentation especially for teeming and customizing their components.
My project looks like:
.src
--app
--components
--login-component
login-component.html
login-component.scss
login-component.js
--login-component
home-component.html
home-component.scss
home-component.js
--and so on ...
app.component.html
app.component.scss
app.component.ts
app.module.ts
app.routing.ts
--assets
--environments
--scss
styles.scss
_material2-theme.scss
_variables-scss
_utilities.scss
_reset.scss
favicon
index.html
and so on ....
In angular-cli.json I have modified the styles to look at scss/style.scss
...
"styles": [
"scss/styles.scss"
]
...
the _material2-theme.scss looks like:
//////////////////////* THEMES */ Custom Blue Theme*/
#import '~#angular/material/theming';
#include mat-core();
$app-primary: mat-palette($mat-light-blue);
$app-accent: mat-palette($mat-light-blue, A200, A100, A400);
$app-theme: mat-light-theme($app-primary, $app-accent);
#include angular-material-theme($app-theme);
/*default palette forground/background*/
$light-foreground-palette: map-get($app-theme, foreground);
$light-background-palette: map-get($app-theme, background);
$primary: map-get($app-theme, primary);
$accent: map-get($app-theme, accent);
and inside of style.scss I am importing everything to be compiled with scss cli compiler
//////////////////////* CUSTOM */
#import "_material2-theme.scss";
#import "_reset.scss";
#import "_utilities.scss";
//////////////////////* COMPONENTS */
#import "~app/components/login/login.component.scss";
My question is after the scss is compiled we have in html head many style tags some of them duplicated and look like:
Everything seems to be compiled in one style that is added in head(tha one that has type attribute) and and after that each scss component splited in each css component with its separate style in head, and that is very weird. I am doing something wrong or is just tha way is working material2?
The behavior you're seeing is caused by ViewEncapsulation.Emulated defined for material components.
First, you don't need to add styles for components to the global styles "scss/styles.scss":
//////////////////////* COMPONENTS */
#import "~app/components/login/login.component.scss";
If you do that, besides your styles getting duplicated you will lose style encapsulation because styles added for components/login/login.component.scss will become global.
Now, to the question why there are many style elements. When you use ViewEncapsulation.Emulated, and it's a default view encapsulation mode, Angular will put each component's style into its own style tag and add attribute to elements inside a component template. In material all components use emulated encapsulation mode so for each component the style tag is added.
If you add #Component({..., encapsulation: ViewEncapsulation.Native }) for your components, you will see the style for your components will be removed.
Here is the logic that adds the style tag:
export class DomSharedStylesHost extends SharedStylesHost implements OnDestroy {
...
private _addStylesToHost(styles: Set<string>, host: Node): void {
styles.forEach((style: string) => {
const styleEl = this._doc.createElement('style'); <--- creates a style element
styleEl.textContent = style;
this._styleNodes.add(host.appendChild(styleEl));
});
}
In Material design for Angular the stylesheet is split into:
style - margins, paddings etcetera that is linked from the component
theme - mostly colors that is build using the theme scss
typography - fonts & font properties that is built using the typography scss
This causes similar selectors, but with different properties inside.
I think it is the live development server that comes with angular cli or webpack that loads css dynamically which causes duplication of style tags. I believe this is not happening in a production build.
PS. Strange of you to add _reset.scss after anything else.
I do not think it is due to having separate styles for each component.
This issue is similar to what's there in a ngularjs-material as well.
Angular-material includes some default theme css as a const variable in JavaScript.
You can read a more on this issue ,
https://stackoverflow.com/questions/33466779/how-to-get-rid-off-angular-material-extra-styles-and-css-linked-by-it-forcefull
In development, the angular cli or webpack compiles every css/scss files from each component to a style tag in the HTML page.
ie, in your case: login-component.scss, home-component.scss each will be loaded inside seperate style tags in the HTML page.
All these will be compiled into a single css file and will be linked in index.html in production conf.
So I too think its the way angular works!
Currently I see that there is only one file generated in production build ng build --prod .
There are multiple style tag in your head may be your every component is linked with some external different css Or you have written internal css at related HTML page.
If you want that there is only one style tag throughout application then in that case you have to write all style in single file.

Configure js-beautify within a react component

I am using js-beautify (the html-beautify option) to format html that is being displayed on my page, it displays but it's collapsing all the html to 1 line which is obviously not ideal because it's a pain to read. It is basically trying to format HTML as Javascript because the actual html beautify is not being applied.
I'm using it in react as below inside a specific component file for that item does anyone know how to fix this?
import htmlBeautify from 'js-beautify'
const htmlString = htmlBeautify(renderToStaticMarkup(<Component />))
export default () =>
<Example staticMarkup={htmlString}>
<Component />
</Example>
Update:
<Example/> is another component that renders out a bunch of additional stuff like a markdown description.
I'm using https://github.com/alexlande/react-style-guide to create a styleguide and passing the static html markup to staticMarkup prop to display rather than just showing the react component which in this context isn't particulary useful.

Categories