Target a css class in 'a component generated by library' in react - css

I have used a chart library. I want to target and modify the properties of the CSS class generated by that library using external CSS. Let's assume the code in inspector is like this-
<div id="apexcharts9xagqubx" class="apexcharts-canvas apexcharts9xagqubx apexcharts-theme-light" style="width: 319.5px; height: 200px;">
<svg id="SvgjsSvg1001" width="319.5" height="200" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.dev/svgjs" class="apexcharts-svg apexcharts-zoomable hovering-zoom">
<div>
the apex chart documentation says I can target .apexcharts-canvas and change the background color. I have done this:
import React from "react";
import ReactApexChart from 'react-apexcharts'
import './apex.module.css'
return (
<div id="chart">
<ReactApexChart options={data.options} series={data.series} type="area" height={200}/>
</div>
);
inside apex.module.css I did this:
.apexcharts-canvas{
background-color: black;
}
now what?
looks like it doesn't work.

It looks like a CSS specifity thing.
You could try including the parent in the selector:
#chart .apexcharts-canvas {
background-color: black;
}

Hey friend when you import a css file with module prefix you shouldn't import that way, that kind of file will be imported giving it a name for example in this image:
This works equally with css extension files, since I am doing it with scss, this rule is for all css file types.
When you declare with module it's not a global style anymore but a style for a component because there is another way to import it but without the prefix module, in the image I already showed you the name of the declared name and then the name of the class.
Luckily my friend, it is not so complicated, I am also learning this little by little.

IF you are using CSS modules (else let me know):
TL;DR
You can either target the HTML element (instead of its class) where .apexcharts-canvas class is used (option 1), or you can make sure the global CSS imports are compatible with the CSS modules (option 2), checking webpack configuration.
I had same issue, I wanted to edit a CSS class in Apexcharts.
I am assumming you are using CSS modules (.module.css).
Option 1
Use this option if:
you used cra or you do not want to edit webpack configuration
it is enough to target the HTML element instead of the class directly
Steps:
The ID of the div where the chart is should be namespaced (CSS modules): id={styles.chart}, with CSS modules file imported as import styles from 'path-to-file'
In code inspector find div with chart id
Drill down until you find HTML element with your class .apexcharts-canvas
In your CSS modules file, target the HTML element with .apexcharts-canvas, using CSS selectors (example below)
.chart > div > div > :last-child {
background-color: black;
}
Option 2
Use this option if:
you can access the webpack config file (not using cra), AND
you want to target class directly
In the webpack configuration, you need to create a rule not only for CSS modules (import styles from 'path-to-file'), but also for global (normal) CSS (import 'path-to-other-file').
(credit: link)
rules: [
{
test: /\.(css|scss)$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: {
localIdentName: "[name]__[local]___[hash:base64:5]",
},
}
}
],
include: /\.module\.css$/
},
{
test: /\.(css|scss)$/,
use: [
'style-loader',
'css-loader'
],
exclude: /\.module\.css$/
},
]
After that you can import a global CSS file (import 'path-to-other-file') with a class .apexcharts-canvas on it.
Important: the webpack rules are mutually exclusive. Files ending with ".module.css" are considered CSS modules, other CSS files not ending like that are global CSS imports.

Related

adding dynamic class name in svelte

I am currently writing an app with svelte, sapper and tailwind. So to get tailwind working I have added this to my rollup config
svelte({
compilerOptions: {
dev,
hydratable: true,
},
preprocess: sveltePreprocess({
sourceMap: dev,
postcss: {
plugins: [
require("tailwindcss"),
require("autoprefixer"),
require("postcss-nesting"),
],
},
}),
emitCss: true,
})
All in all this works, but I am getting some issues with dynamic class names.
Writing something like this always seems to work
<div class={true ? 'class-a' : 'class-b'}>
both class-a and class-b will be included in the final emitted CSS and everything works as expected.
But when I try to add a variable class name it won't work. So imagine this:
<div class={`col-span-6`}>
It will work exactly as expected and it will get the proper styling from the css class col-span-6 in tailwind.
But if I change it to this:
<div class={`col-span-${6}`}>
Then the style won't be included.
If I on the other hand already have a DOM element with the class col-span-6 then the styling will be added to both elements.
So my guess here is that the compiler sees that the css is not used and it gets removed.
And I suppose that my question is then if there is any way to force in all the styling from tailwind? so that I can use more dynamic class names
and not sure if it is relevant but the component I have been testing this on, have this style block
<style>
#tailwind base;
#tailwind components;
#tailwind utilities;
</style>
edit: can add that I am getting a bunch of prints in the log saying that there are unused css selectors that seems to match all tailwind classes
I think it was purgeCSS (built-in in tailwind 2.0) that did not recognize the dynamic classes.
It is difficult to solve this problem for every tailwind classes, but if you don't have a lot of these you can manually safe list those classnames:
// tailwind.config.js
module.exports = {
purge: {
content: ['./src/**/*.html'],
// These options are passed through directly to PurgeCSS
options: {
// Generate col-span-1 -> 12
safelist: [...Array.from({ length: 12. }).fill('').map((_, i) => `col-span-${i + 1}`],
},
},
// ...
}
I think that when the class attribute is a variable or depends on a variable it will not used to extract style during compilation (class-${6} is not evaluated during compilation but during runtime), because svelte marks it as unused css selector because the value of that class attribute is not known when the code is compiled.
To force svelte to include your style you must mark it as global, and to do that we have two options:
<script>
// component logic goes here
</script>
div class={`class-${6}`}/>
option 1:
<style>
:global(.class-6){
// style goes here
}
</style>
option 2: this will mark all your style as global
<style global>
.class-6{
// style goes here
}
</style>
I encounter the same problem, <div class="pl-{indent*4}"> do not work in svelte.
My solution is to use inline style,
<div style="padding-left:{indent}rem">,
which is inferred from pl-1=padding-left: 0.25rem; /* 4px */.
I think it's convenient for simple class.

Is there a way to fetch colors stored from the Back End and place them in SCSS file

At the moment i'am currently re-factoring my code . So that means more clearness and higher maintance . I have an idea in my head , but unfortunately i don't know how this can be realeased.
In order to be more clean and effecient i want to create an isolated _colors.scss file that will contain all of my colors for the app . In other words i want it to look something like this
$colorPrimary: branding.colorPrimary,
$colorSecondary: branding.colorSecondary
...
At the moment is pretty messy because the color styling is maintened at the component level , but i want to do this seperately .
Ex:
<button style={
color: branding.colorPrimary,
background: branding.colorSecondary>
Hello
</button>
The colors are stored on the BE side so if i want to react them i have to do a call . I will be glad if someone can give me a hand with this mindf****. Thank you .
to acheive this behavior you have two main way to do it. the first one describe are not compatible with Internet Explorer.
On last CSS version describe on W3C we are able to have variable directly on CSS.
Like this backend can do something like this :
<head>
<style type="text/css">
:root {
--primary-color: #cecece;
--secondary-color: #fefefe;
}
</style>
</head>
then on your scss (or css) you can do something like :
.mySelector {
color: var(--primary-color, black);
}
which will be basically interpret as :
.mySelector {
color: #cecece;
}
Or fallback in color black if --primary-color is not defined.
As you can imagine, is very easy for backend to prepare the configuration for frontend. And from your side (as front end) you can simply use what is already available on CSS API tools.
But if you are looking for something which are compatible with IE. You probably need more complex infrastructure.
Goal is to spawn webpack sass compilation, on each User color change,
to build css output with relevant variable configuration.
for that you will need SaSS ressource loader which automatically inject sass file on all other file. Is like adding #import "_colors" automatically.
then backend server will have to :
Write _color.scss file somewhere (let say /user/123/_color.scss)
Ask for compilation like webpack client 123
read the output webpack folder for client 123 and detect if specific CSS exist
Inject on your head HTML.
For webpack configuration
on your webpack you will have something like :
const argv = require("yargs").argv;
entry: {
[...]
},
output: {
// Take the argument as clientId and craft dedicated output folder.
path: helpers.root(`public/themes/front/${argv.client}`),
filename: "[name].[contenthash].js",
chunkFilename: "[name].[contenthash].js"
}
Like this base on the client id you will store the outputed CSS on specific folder.
Finally the SaSS rules will looks like :
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'postcss-loader',
'sass-loader',
{
loader: 'sass-resources-loader',
options: {
resources: (argv.client) ? `/user/${ argv.client }/_color.scss` : `/user/default/_color.scss`,
},
},
],
}

How to create and style svelte 3 custom elements with nested components?

I'm trying to create custom-element (web component) in svelte 3. I can't find any way to style nested components from css. Svelte removes styles before injecting them to <style> inside of ShadowDOM.
The problem is that I want to have nested components in my root element.
For example:
RootComponent (svelte custom-element)
(imports) FooComponent
(imports) BarComponent
As stated here: svelte-custom-element
All the components imported to custom-element must have compiler option set to <svelte:options tag="component-name" />.
With this option set nested components works as expected and are injected into root's element ShadowDOM. The problem is that styles defined in nested components are not being injected.
The workaround for this problem would be to inject them into root's element <style> as global styles within ShadowDom.
(Un)fortunately svelte automatically removes all unused styles during compilation when custom elements not yet exist.
My goal is to create web component with svelte and then use it outside of svelte as native web-component.
Here is REPL
Custom elements do not really work on REPL as Conduitry wrote:
The compiler options in the REPL don't actually affect the code that >is run, just the code that is displayed. So enabling customElement >doesn't mean you are building and running a web component
So it's more like a code example than working one.
I would like to know if there is another way to create svelte custom-element with nested component and proper styling.
Is there a way to disable removing of unused css?
https://imgur.com/a/zZia566
from <div class="nested"> starts Nested component imported from Nested.svelte.
<style> element should have .nested class injected but it is removed by svelte compiler.
This is because when customElement option is on, each style in a component is injected into the shadowRoot of the custom element.
class YourComponent extends SvelteElement {
constructor(options) {
super();
this.shadowRoot.innerHTML = `<style>.foo{color:red;}</style>`;
// continues
Thus, in order to make style appear, you must use svelte component as custom element, not as svelte component.
Your App.svelte should be like below.
<script>
import Foo from './Foo.svelte'
import Bar from './Bar.svelte'
</script>
<svelte:options tag="web-component" />
<foo-component/>
<bar-component/>
However, this neither solve the problems related with custom element.
:global selector is not transformed into actual global selector.
Every nested component will produce shadowRoot, whereas mostly you will want only top-level one.
Check out some issues below from svelte repository related to custom elements.
nested component in custom element does not inherit style #2605
:global(...) not working in custom elements #2969
It seems like svelte does not fully support style cascading in custom element yet, should be handled in future.
Checked in svelte v3.12.1.
Thanks to brunoalano for sending me this: svelte-custom-element-template. It solves the styling problem with custom build script.
You just have to prevent the compiler from removing unused CSS
Let's say we have a custom element : App.svelte
App.svelte imports a normal svelte component : ./components/Message.svelte
But when you do this, any styles inside Message.svelte will disappear.
Solution
Move all content in the <style> tag of Message.svelte into the <style> tag of App.svelte
Add this to script of App.svelte
let cssKeep: string = "";
Add this to body of App.svelte
<span style="display: none;" class={cssKeep}><span class={cssKeep} /> </span>
This will prevent the compiler from removing any styles
Example
src/components/Message.svelte
<script lang="ts">
export let content: string;
</script>
<p class="red"> {content} </p>
src/App.svelte
<svelte:options tag="my-element" />
<script lang="ts">
import Message from "./components/Message.svelte";
let cssKeep: string = "";
</script>
<Message content="hello" />
<span style="display: none;" class={cssKeep}><span class={cssKeep} /> </span>
<style>
.red {
color: red;
}
</style>
vite.config.ts
import { defineConfig } from 'vite'
import { svelte } from '#sveltejs/vite-plugin-svelte'
export default defineConfig({
build: {
lib: {
entry: './src/main.ts',
name: 'MyElement'
},
},
plugins: [
svelte(
{
compilerOptions: {
css: true,
},
exclude: "./src/App.svelte",
emitCss: true,
}
),
svelte(
{
compilerOptions: {
customElement: true,
css: true,
},
exclude: "./src/components/**",
emitCss: true,
}
),
],
})
// guide: https://www.thisdot.co/blog/web-components-with-svelte
This may answer:
How to export web component in Svelte with nested Svelte components
Use Svelte components with custom elements
Styles missing when Svelte component imported into custom web component / custom element

React/Webpack applying styles to tags but not classes/ids

I have setup my own react project from some tutorials including my own webpack configuration. When I try to style elements it is able to apply style to generic html tags such as <body> or <p> but it fails when I try to style classes/ids.
I know my css file is being imported because it styles the generic tags.
Webpack Config
{
test: /\.css$/,
use: [
"style-loader",
{
loader:"css-loader",
options:{
modules:true
}
}
]
}
CSS
.oakResults {
font-size:20px;
}
#yoyoyo {
color:red;
}
p {
color:orange;
}
React
<div className='oakResults'>
<p id='yoyoyo'>Results</p>
</div>
In my example, the <p> is colored red, but .oakResults font does not change and when I comment out the <p> style it doesn't turn red.
I want it to be able to style to both generic tags and classes/ids.
I think the reason of this issue is you have enable the css modules in webpack but not referring the css correctly.
So if you don't need the css module, try to remove options:{ modules:true} from your webpack config. Then the css could be applied to the class name you set in ReactJS.
Or if you do need the css module, keep the Webpack config. But modify your ReactJS to something like this:
import React, { Component } from 'react';
import styles from 'path\to\file.css';
class foo extend Component {
render() {
return (<div classname={styles.oakResults}> This is the test component</div>)
}
}
Hope it helps.
You should try this,
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
From the docs,
The modules option enables/disables the CSS Modules specification and setup basic behaviour.
Using false value increase performance because we avoid parsing CSS Modules features, it will be useful for developers who use vanilla css or use other technologies.
Refer more about CSS Modules.

Using css-loader inline with Webpack + React

I'm building my React app with Webpack, and css-loader w/modules. I love it. Most of my stylesheets are very small, though, and I'd like to inline them within the same JSX file as my markup and JavaScript.
The CSS loader I'm using right now looks like this:
{ test: /\.(css)$/i,
loader: ExtractTextPlugin.extract("style-loader", "css-loader?modules") }
In my JSX, I import my separate CSS files like this:
import classNames from 'dashboard.css';
...
<div className={classNames.foo}></div>;
This is then compiled and translated into something like:
<div class="xs323dsw4sdsw_"></div>
But what I'd like to do is something more like below, while still preserving the localized modules that css-loader gives me:
var classNames = cssLoader`
.foo { color: blue; }
.bar { color: red; }
`;
...
<div className={classNames.foo}></div>;
Is this possible? How can I do this without having to actually require / import a separate file?
I believe your issue is that you your current webpack configuration uses CSS Modules. CSS Modules automatically rename your CSS Classes to avoid global class name collisions.
The fix:
// remove 'modules' from the end of your css-loader argument
{ test: /\.(css)$/i,
loader: ExtractTextPlugin.extract("style-loader", "css-loader?modules") }
// like so
{ test: /\.(css)$/i,
loader: ExtractTextPlugin.extract("style-loader", "css-loader") }
Now your class names will be preserved. Although, I'm not sure why you want to do this. Do you care to share why?

Resources