How to import CSS file content into a Javascript variable - css

Consider a very simply custom element using shadow DOM:
customElements.define('shadow-element', class ShadowElement extends HTMLElement {
constructor() {
super();
this.styleTag = document.createElement('style');
this.styleTag.textContent= `
.root::before {
content: "root here!";
color: green;
}
`
this.shadow = this.attachShadow({mode: 'closed'});
this.root = null;
}
connectedCallback() {
this.root = document.createElement('div');
this.root.className = 'root';
this.shadow.append(this.root, this.styleTag);
}
})
<shadow-element></shadow-element>
To get the CSS into the shadow DOM, I create a style tag, which I append into the shadow root. This is all working fine so far.
Now for more complex CSS I would like to author it in a file shadow-element.css which is in the same folder as shadow-element.js. Besides seperation of concerns I also want IDE syntax highlighting and -completion for CSS authoring, so I really want the CSS in a separate, dedicated file.
I want to import the contents of that CSS file into a Javascript variable, like
import styles from './shadow-element.css'; // obviously doesn't work
On the project where this is being used we have a working webpack stack that allows importing CSS (and even SCSS), but unfortunately that imported CSS then becomes part of bundle.css - which obviously is not at all useful, because the element uses shadow DOM.
Does anyone have a solution to this? I'm also open to alternative solutions, as long it won't require me to author my CSS in a .js file.
Edit: I am aware of the option of using #import './shadow-elements.css'; inside the style tag, but I would much prefer a solution that bundles the imported CSS into my Javascript bundle (as part of the component code).

As you are using webpack, you can use raw-loader to import a text file (CSS in your case) into a string:
npm install raw-loader --save-dev
And you can use it inline in each file:
import css from 'raw-loader!./shadow-element.css';
customElements.define('shadow-element', class ShadowElement extends HTMLElement {
constructor() {
super();
this.styleTag = document.createElement('style');
this.styleTag.innerText = css;
this.shadow = this.attachShadow({mode: 'closed'});
this.root = null;
}
connectedCallback() {
this.root = document.createElement('div');
this.root.className = 'root';
this.shadow.append(this.root, this.styleTag);
}
})

Related

Can I use css modules in react class based components?

I have to implement css modules for some older React code. But when I try to import CSS modules, I canĀ“t use this class in another files.
Do I have to refactor the code to React Components? Or is there another easier solution?
Code example:
import styles from "styles.module.css"
var Greeting = createReactClass({
render: function() {
return <h1>Hello</h1>;
}
});
Yes, module CSS is also supported in class-based components.
In the module CSS you have to use CSS as an object,
For Example, You have a CSS class for an alert component
.alert{
color:red
}
then you can use it in components like this:-
import styles from "styles.module.css"
var Alert = createReactClass({
render: function() {
return <h1 className={styles.alert}>Hello</h1>;
}
});

Selector ":root" is not pure (pure selectors must contain at least one local class or id) - NextJS with SASS modules

I've recently been switching to using modules in my next.js project, but I keep receiving this error in my newly created .module.scss files: "Selector ":root" is not pure (pure selectors must contain at least one local class or id)". I know this is because I'm not using pure css selectors as I've seen elsewhere online, and the only problem is the imports that I'm using, but I need those imports for variables like $cl-light-gray as seen below in this example file:
#import "src/common/styles/global-styles.scss";
#import "node_modules/bootstrap/scss/bootstrap";
#import "src/common/styles/palette.scss";
#import "src/common/styles/typography.scss";
.dashboard-dropdown-hover {
#extend .px-1;
#extend .py-2;
#extend .mt-3;
border: 1px solid transparent;
border-radius: 8px;
transition: 200ms;
background-color: transparent;
}
.dashboard-dropdown-hover:hover {
background-color: $cl-light-gray;
}
Does anyone have a solution to how I should fix this import problem? I know that if I switch back to .scss it will work, but I'm trying to avoid importing all the .scss files in _app.tsx because that would be at least 30 imports and also these styles aren't intended to be global. Lastly, why does Next.js expect me to use pure css selectors when I'm using Sass, which is used because of its non-pure elements?
After scouring the internet for a few hours I found a great solution from here: https://dhanrajsp.me/snippets/customize-css-loader-options-in-nextjs
EDIT: If you're using Next.js 12, check the bottom of the article above, because the solution is a little different.
You'll want to change your next.config.js file to include the following:
/** #type {import('next').NextConfig} */
require("dotenv").config();
const regexEqual = (x, y) => {
return (
x instanceof RegExp &&
y instanceof RegExp &&
x.source === y.source &&
x.global === y.global &&
x.ignoreCase === y.ignoreCase &&
x.multiline === y.multiline
);
};
// Overrides for css-loader plugin
function cssLoaderOptions(modules) {
const { getLocalIdent, ...others } = modules; // Need to delete getLocalIdent else localIdentName doesn't work
return {
...others,
localIdentName: "[hash:base64:6]",
exportLocalsConvention: "camelCaseOnly",
mode: "local",
};
}
module.exports = {
webpack: (config) => {
const oneOf = config.module.rules.find(
(rule) => typeof rule.oneOf === "object"
);
if (oneOf) {
// Find the module which targets *.scss|*.sass files
const moduleSassRule = oneOf.oneOf.find((rule) =>
regexEqual(rule.test, /\.module\.(scss|sass)$/)
);
if (moduleSassRule) {
// Get the config object for css-loader plugin
const cssLoader = moduleSassRule.use.find(({ loader }) =>
loader.includes("css-loader")
);
if (cssLoader) {
cssLoader.options = {
...cssLoader.options,
modules: cssLoaderOptions(cssLoader.options.modules),
};
}
}
}
return config;
},
};
I'm not seasoned with webpack or how it exactly works, but this solution worked for me. You can also change the regex to include css by doing (scss|sass|css) if you want.
As pointed out here, there is another option: you can import those styles in the global.css file. If you do that, Nextjs will be happy.
Any global styles (e.g., :root or any HTML elements/CSS classes that you want to have the same style absolutely everywhere in your app) should be placed into a global CSS file that you import into _app.js (which you just can add to the root folder of your project, if it doesn't already exist).
This global CSS file is also where you want to import any fonts that you will use app-wide.
Step-by-step instructions here: https://nextjs.org/docs/basic-features/built-in-css-support
In my particular case i was having the same headache with that issue, and was because i was trying to import the file with the path:
/node_modules/bootstrap/scss/bootstrap-utilities.scss
and that file was importing another file called _root.scss which was defined a selector in this style.
:root{
}
for solution that error i simply import the specific files used for my requirements
Another resources could help you:
https://www.youtube.com/watch?v=dOnYNEXv9BM&t=1044s
https://sass-lang.com/documentation/modules
https://dev.to/mr_ali3n/use-forward-in-sass-2bab

How to override external module class with css module pattern in react

I want to override a external module cssclass locally for a component
In my code
import `style` from './style.module.css' // this is local css module
import `ExternalComponent` from 'ExternalComponent' // suppose this is external module i'm using
function Component(){
return(
<ExternalComponent/>
)
}
Now the ExternalComponent render a div element with a class parent. So if i am importing the
ExternalComponent how can i override the parent class of ExternalComponent in my locally imported style module so that the style in the ExternalComponent change only for this component
only and else where i'm using it does not change.
I'm using react by the way.
style.module.css
.whatever-name-scope {
:global {
.parent {
// override here
}
}
}
Then your jsx goes:
function Component(){
return (<div className={style.whateverNameScope}>
<ExternalComponent/>
</div>)
}

How to compile component styles dynamically in Angular 6

I'm trying work out a way to use jss in an angular 6 project to allow dynamic styling of components.
The issue I'm running into is that the dynamic styles are always less specific than the predefined styles, because the dynamic styles are missing the attribute selector from the view encapsulation system.
I can easily get the raw CSS output from jss, but I haven't been able to find a way to run this through the angular compiler to have the selectors modified to include the attribute selector.
Ideally I'd like to be able to bind a <style> tag in the template to a cssText property of the component, but this doesn't seem possible.
import {Component, OnInit} from '#angular/core';
import * as color from 'color';
import jss from 'jss';
#Component({
selector: 'app-example',
template: `
<p [ngClass]="cssClasses">TEST TEST</p>
`,
styleUrls: ['./example.component.scss']
})
export class ExampleComponent implements OnInit {
cssClasses: { [name: string]: boolean } = {};
constructor() {
}
ngOnInit() {
const {classes} = jss.createStyleSheet({
dynamicClass: {
color: color('blue').hex(),
}
}).attach();
this.cssClasses[classes.dynamicClass] = true;
}
}
example.component.scss
p {
color: 'red'
}
If there a way of invoking the angular CSS compiler on an arbitrary piece of CSS, with the context of a particular component?
Or another way to achieve what I'm describing above?
Note: I'm aware that I can bind and apply inline styles to elements, but this doesn't meet my requirements - in particular you cannot target pseudo selectors, or do media queries etc using this mechanism.
I could probably work around this by not using the scss file at all and defining all default styles through the jss mechanism however I would prefer to retain the ability to use the normal style system so that the jss is only used where needed. Also I think I would still run into selectivity issues when styling 3rd party components using jss.

CSS className isn't making any changes to Reactjs

I'm currently working with rails and reactjs. I'm having difficulties using css in my reactjs files. It seems like every time i try to use it, no change is being applied at all. In my App.jsx file I have this:
import React from "react";
import styles from "./styles.css";
export default class Register extends React.Component {
render() {
return (
<div className={styles.container}>
<h1> this text should appear to the right </h1>
</div>
);
}
}
And in my styles.css file I have this:
.container {
width:40%;
text-align:right;
}
For the record I am using webpack. Can anyone help me understand why the css isn't having any effect on my jsx components. I've looked all over for help but was unable to put the pieces together.
If it matters, this is how my "config/webpack/development.js" file looks like:
process.env.NODE_ENV = process.env.NODE_ENV || 'development'
const environment = require('./environment')
module.exports = environment.toWebpackConfig()
It depends on the webpack loader settings. If you are using css-loader as configured in react-scripts (as of 1.1.5), then the classNames are loaded using {modules: false} option, i.e. global styles, which can be referenced as strings in JSX code:
import "./styles.css";
... className="container" ...
Or you can load local styles using following CSS-file syntax:
:local .container {...
Or edit your webpack.config.js appropriately (see https://github.com/webpack-contrib/css-loader#scope for the official documentation of various options).
seems like you didn't enable an option { modules: true } for css-loader in webpack config
take a look
webpack-contrib/sass-loader#206
https://github.com/webpack-contrib/css-loader#options
Taken from: https://github.com/facebook/create-react-app/issues/1350

Resources