vuejs multiple themes with scoped css in single file vue components - css

So let's assume we have a variables scss file like the following
$darken-percentage: 15%;
$primary-color: #2aaae1;
$dim-primary-color: darken($primary-color, $darken-percentage);
$complementary-color: #faaf48;
$dim-complementary-color: darken($complementary-color, $darken-percentage);
$background-color: #1d1f29;
$middleground-color: #313444;
$dim-middleground-color: darken($middleground-color, $darken-percentage);
$light-middleground-color: lighten($middleground-color, $darken-percentage);
In the main.js we could use #import 'variables.scss'
what if I have two themes and I want to change on user action I could have 2 variables files and conditionally import either based on user actions but what about single file vue components
like
<style scoped lang="scss">
#import '../../theme/_variables.scss';
.bm-upload{
background: $primary-color;
}
</style>
Then the import will not work so is there anyway for me to have global variables files and use it in other files without re importing it

The easiest is to import both style files and change a parent element's class. The browser will immediately apply the styles when the class changes.
You can, for example, change the body's class with classList and have all styles depend on that.
created(){
let body = document.getElementsByTagName('body')[0];
body.classList.add("theme1");
},
methods: {
changeTheme(){
let body = document.getElementsByTagName('body')[0];
body.classList.remove("theme1");
body.classList.add("theme2");
}
}
Style should inherit from the theme class name, like this:
.theme1 {
.exampleClass {
padding: 0;
}
}

Related

how to call Sass variable in a Vue file

There is a variables.scss file in a project which defines a variable and assigns it a color like this:$contrast: #edebe4The current use of the $contrast variable is to set other variables within the variables.scss file.
Now there is a specific .vue file that's used to render data to the browser and it contains this line of code in its template:<div style="background-color: #edebe4">
When I change that line to<div style="background-color: $contrast">the desired background color disappears from that element.
Is there a way to get that element to recognize the $contrast variable so that whenever the value of $contrast is changed that change flows through automatically to this element?
You can make scss variables available globally (in each component). Just add this to vue.config.js:
css: {
loaderOptions: {
scss: {
additionalData: `#import "~#/variables.scss";`
}
}
}
More info here
Just import variables.scss into your .vue
...
<style lang="scss">
#import "variables.scss"
</style>
This worked -
in variables.scss file added
.contrast-background {
background-color: $contrast;
}
in .vue file changed element to this
<div class="contrast-background">
Amendment -
Here is the final solution that was implemented, which was made possible by #Finn's post -
Changes to .vue file:
added this
<style lang="scss" scoped>
#import "#/layout/design/variables.scss";
.contrast-background {
background-color: $contrast;
}
</style>
and changed element to this
<div class="contrast-background">
This approach avoids changes to the variables.scss file.

Vue3 - How to override styles after importing node_modules css file?

I have a standard Vue3 app using the library https://github.com/ismail9k/vue3-carousel.
In my App.vue file, I have the following, which is required to use the library:
<style>
#import "~vue3-carousel/dist/carousel.css";
</style>
Since I don't want to use the library's default colors, I'm trying to override some styles.
The library defines some colors on :root, such as:
--vc-clr-primary: #333333;
--vc-pgn-background-color: var(--vc-clr-primary);
Then, the style that I want to ultimately override is:
.carousel__pagination-button {
...
background-color: var(--vc-pgn-background-color);
}
So, I assume that I want to override either of the variables, or the class itself. In my Component.vue file, I have the following:
<style scoped>
.carousel__pagination-button {
background-color: #999999 !important;
}
</style>
But that doesn't do anything.
I don't care where I override these colors, because I'll use the same colors throughout the website, but I can't figure out how to get them to override no matter where or how I attempt to override them.
What am I doing wrong?
This worked:
App.vue
...
<style>
#app {
--vc-pgn-background-color: #mycolor;
}
#import "~vue3-carousel/dist/carousel.css";
</style>

Applying CSS stylesheet only to active component

I'm working on a ReactJS app that has a header at the top, a menu on the left, and the "frame" in the middle is where routes and their corresponding components are loaded. I want to be able to apply a CSS stylesheet to specific components only when they are loaded. I also don't want them applied all the time or to the top header or left menu.
My expectation was that adding import 'custom.css'; to a specific component would only apply the stylesheet's styles to that component and it's children when the route is active. Instead, it applies it to the entire page even when the route/component are not loaded.
I understand that an alternative approach is styled components, but, for my use-case, a design company is supplying a stylesheet (which should remain unchanged) that we need to consume only for the sub-module I'm working on and I don't want its styles to affect the rest of the app.
How can I have a stylesheet only applied to my active route/component?
Use simple CSS technique. Suppose you have two components with different css files (say about.css and contact.css). Now consider your both CSS file have one common class with different style properties, like:
about.css
.container{
max-width: 400px;
}
contact.css
.container{
max-width: 500px;
}
Yes in ReactJS both the CSS files will load at the same time and will override any one of the style. so to solve this problem add class to differentiate this styles, like:
about.css
.about-component.container{
max-width: 400px;
}
contact.css
.contact-component.container{
max-width: 500px;
}
If you want apply only when the component is mounted, you can use the lifecycle.
The follow example is based in the idea you are using sass, React, sass-node and have the loaders into webpack.
<pre>
import React from 'react';
import './styles.scss';
class MyComponent {
constructor(props) {
super(props);
this.state = { className: '' }
}
componentDidMount() {
this.setState({
className: 'myOwnClass'
});
}
render(){
return (
<div className={this.state.className}>This is a example</div>
);
}
}
export default myComponent;
</pre>
To be able to only call that specific CSS when you need it you can use CSS Modules. You may need to update your version of react.
When saving your CSS file save it with a ".module.css" eg. "styles.module.css". The CSS in these files can only be used and accessed by hte components where are they are imported. As stated in a tutorial from W3Schools.
Let's say this is your CSS code in styles.module.css:
.container {
color: white;
}
.cont-child {
background-color: red;
}
Then in your JS file you can import the CSS file like this if the JS and CSS files are in the same directory. Make sure you point to the correct path.
import styles from './styles.module.css'
Then in your HTML section you can use it like this:
class Home extends React.Component {
render() {
return(
<main className={ styles.container } >
<div className={ styles["cont-child"]} >
Some div text about something...
</div>
</main>
);
}
}
I currently use both ways to access the selectors, since the styles variable acts like an object. I placed both of them here because the second option is capable of fetching selectors named like "btn-active". Which comes in handy in some situations. Camelcasing is considered cleaner though.
Please note: I originally posted this answer as a reply to a similar question here React CSS - how to apply CSS to specific pages only
I want to be able to apply a CSS stylesheet to specific components
only when they are loaded.
Why not apply the styles inline via React.js?
Step 1. Create the style object for the component:
var componentOneStyle = {
color: 'white',
backgroundColor: 'red'
};
Step 2. Populate the component's style attribute with the style object:
ReactDOM.render(<div style={componentOneStyle}>This is Component One</div>, mountNode);

How to make React CSS import component-scoped?

I have several components which have the following CSS/component structure
About/style.css
.AboutContainer {
# Some style
}
p > code {
# Some style
}
And I import the CSS in the componet as follows
About/index.js
import './style.css';
export default class About extends Component {
render() {
# Return some component
}
}
However, the CSS is imported in the <header> section and stays global-scope.
I was expecting CSS to be:
Component-scoped in a way that the style is only applied to things that are only rendered within this component.
Style for this component would disappear if the component is unmounted.
However, when inspecting from the browser, the styles are specified at the <header> section and gets applied to all the components
<header>
// Stuff
<style type="text/css">style for component About</style>
<style type="text/css">style for component B</style>
<style type="text/css">style for component C</style>
// Stuff
</header>
How do I import CSS to be component-scoped? It seems like I'm understanding CSS import in React ES6 incorrectly.
I was following this tutorial
Edit
Answer by Brett is correct. However, my problem turns out to be somewhere else. I created my app using create-react-app which basically simplifies setups required to do React. It include WebPack, Babel and other things to get started. The default WebPack config that it uses did not set module option for the css-loader so it defaulted to false, and as a result the local-scoping was not enabled.
Just for additional info, it seems like create-react-app does not have straightforward way to customize WebPack config, but there seem to be numerous how-to workarounds on the web.
It sounds like CSS Modules, or many of the other CSS-in-JS packages, does what you want. Others include Emotion (my current favorite), Styled Components, or many of the packages here.
A CSS Module is a CSS file in which all class names and animation names are scoped locally by default. All URLs (url(...)) and #imports are in module request format (./xxx and ../xxx means relative, xxx and xxx/yyy means in modules folder, i. e. in node_modules).
Here's a quick example:
Let's say we have a React component like:
import React from 'react';
import styles from './styles/button.css';
class Button extends React.Component {
render() {
return (
<button className={styles.button}>
Click Me
</button>
);
}
}
export default Button;
and some CSS in ./styles/button.css of:
.button {
border-radius: 3px;
background-color: green;
color: white;
}
After CSS Modules performs it's magic the generated CSS will be something like:
.button_3GjDE {
border-radius: 3px;
background-color: green;
color: white;
}
where the _3DjDE is a randomly generated hash - giving the CSS class a unique name.
An Alternative
A simpler alternative would be to avoid using generic selectors (like p, code, etc) and adopt a class-based naming convention for components and elements. Even a convention like BEM would help in preventing the conflicts you're encountering.
Applying this to your example, you might go with:
.aboutContainer {
# Some style
}
.aboutContainer__code {
# Some style
}
Essentially all elements you need to style would receive a unique classname.
Maybe react-scoped-css will help. Btw, I'm the author of this lib, if you find anything broken or simply want to improve it, you can always raise an issue or send a pr.
Because you mentioned you used create-react-app, the solution here is quite easy change just style.css to style.module.css, it will look like this:
import styles from "./style.module.css"
<button className={styles.button}>blabla</button>
More info on this article:
https://blog.bitsrc.io/how-to-use-sass-and-css-modules-with-create-react-app-83fa8b805e5e
You can use SASS (.scss) to imitate scoped CSS.
Say you need to use bootstrap in only one component (to avoid conflicts). Wrap the component in <div className='use-bootstrap'> and then created a .scss file like so:
.use-bootstrap {
// Paste bootstrap.min.css here
}
Use this file naming convention [name].module.css
and see documentation: https://create-react-app.dev/docs/adding-a-sass-stylesheet
JSX File
import React from 'react';
import styles from './index.module.scss';
const MyPage = () => {
return (
<div className={styles}>
<h1>My Page</h1>
</div>
);
};
export default MyPage;
Styles File
h1 {
color: #f3f3f3;
font-family: "Cambria";
font-weight: normal;
font-size: 2rem;
}
For me, the simple solution (without using: Css-modules or css-in-js) is to add a suffix to your class selectors like this:
className="btn__suffix"
if your component is named: FileUpload.tsx so your __suffix would be __fu, i took the first character of each word (here: File and Upload).
the end result would be:
import './style.css';
export default class About extends Component {
render() {
Return (
<div className="container__fu">
...
</div>
)
}
}
And in the Css part, your file would be:
.container__fu {
...
}
I created a rollup plugin to have scoped scss/css within a vite react project with regular import, you can check it out if it can solve your issue!
https://www.npmjs.com/package/rollup-plugin-react-scoped-css

Making customizable css properties with React and CSS Modules/PostCSS

I'm trying to make a library of react components that's external to an application. This will be an npm module, loaded with Webpack. I'm styling the component using CSS Modules, and I'm trying to see how to make some of its properties customizable. For instace, background color.
I would like to use css variables for this to have for instance this syntax in the css file:
.myClass {
backgrond-color: var(--backgroundColor, red);
}
Where --backgroundColor is a variable I can set, and red is the default. My question is, is there a way I can pass variables to the .css file when loading it from the .jsx file? So I could pass a variables object to the component, which then would influence how it loads it style? Could I use PostCSS for this?
Thanks.
PS: I know this could be solved by using inline JS styles, but I'm trying to give CSS a shot first.
You cannot inject javascript into a css file and PostCSS can only transform your css files, but not inject/replace variables.
However, one way of doing this would be to create .scss (sass) files with default variables, e.g. $background-color: red; One could then import your module and .scss files to their .scss files and overwrite any variables like $background-color with their own variables if they wish.
I'm not sure I understood you right, but here what I'm thinking of:
When you are requiring .css file with Webpack it adds this css as a string to the <head> element of the page behind the scene.
Why don't you do what Webpack does using your own function, like so.
Your module:
import $ from 'jquery';
/* this function builds string like this:
:root {
--bg: green;
--fontSize: 25px;
}
from the options object like this:
{
bg: 'green',
fontSize: '25px'
}
*/
function buildCssString(options) {
let str = ':root {\n'
for(let key in options) {
str += '\t--' + key + ': ' + options[key] + ';\n'
}
str += '}';
return str;
}
/* this function adds css string to head element */
export const configureCssVariables = function(options) {
$(function() {
var $head = $('head'),
$style = $('<style></style>');
$style.text(buildCssString(options));
$style.appendTo($head)
});
}
Usage:
import {configureCssVariables} from './your-module';
configureCssVariables({
bg: 'green',
fontSize: '25px'
});
And your css is simple
/* default variables that will be overwritten
by calling configureCssVariables()
*/
:root {
--bg: yellow;
--fontSize: 16px;
}
.myClass {
backgrond-color: var(--bg);
font-size: var(--fontSize);
}
It can be acheived by adding PostCSS and the postcss-custom-properties plugin in your pipeline. It has a variables option which will inject JS defined variables (properties) to any file being processed.
This eliminate the need to #import anything inside every CSS module file.
const theme = {
'color-primary': 'green',
'color-secondary': 'blue',
'color-danger': 'red',
'color-gray': '#ccc',
};
require('postcss-custom-properties')({
variables: theme,
});
See how to use it with babel-plugin-css-modules-transform https://github.com/pascalduez/react-module-boilerplate/blob/master/src/theme/index.js and https://github.com/pascalduez/react-module-boilerplate/blob/master/.babelrc#L21 but that works with Webpack as well.
I actually found a solution that already does this and takes advantage of the latest standardized JavaScript features
https://github.com/styled-components/styled-components
It may just be what I was looking for.

Resources