Chandler Bing
Chandler Bing

Reputation: 479

How to use color variable in css file on before/after pseudo selectors?

I'm getting a background-color from an API, variable name settings.brand_color. I want to use that variable in html element. I cant use style attribute becuase I'm using :before selector in my app. I want to pass that API variable in my css file and use it in my :before pseudo selector.

JSX

<>
  <input
    type="radio"
    name="language-select"
    className="focus:ring-0  mr-5 my-18p default-style radio__input"
  />
  <div className="radio__radio"></div>
</>;

CSS

.radio__radio {
  width: 24px;
  height: 24px;
  background-color: #d8d8d8;
  border-radius: 50%;
  box-sizing: border-box;
  padding: 6px;
  margin-right: 20px;
  z-index: 1;
}

.radio__radio::after {
  content: "";
  width: 100%;
  height: 100%;
  display: block;
  background: #f28b46;
  border-radius: 50%;
  transform: scale(0);
  z-index: 9;
}

Update
Another solution for this issue is to just use before & after from tailwinds

Pseudo-elements

Upvotes: 10

Views: 3741

Answers (7)

ayushsoni1001
ayushsoni1001

Reputation: 76

The best & easiest possible way is to add style in JSX code.

<input
id={languageLabel}
type="radio"
name="language-select"
value={languageLabel}
// defaultChecked={index === 0}
onChange={() => {
  onLanguageChange(language, languageLabel);
}}
className="focus:ring-0  mr-5 my-18p default-style radio__input"
/>

Just add this part to your JSX File

<style>
    {`
        .radio__radio::before {
        background-color: ${settings.brand_color}
        }
    `}
</style>

Upvotes: 1

J.D. Sandifer
J.D. Sandifer

Reputation: 906

I had a similar problem one time that I actually solved by using another div element instead of the pseudo element. I apologize if that doesn't work for your specific use case, since you said you wanted to use the pseudo element. However, since it seems like you have access to the JS, JSX, and CSS, it might be something you could consider.

The before and after pseudo elements are almost equivalent to div elements placed as the first or last child of the parent element so adding another div like this

<div className="radio__radio">
   <div 
      className="radio__radio__after"
      style={{ backgroundColor: apiColor || '#f28b46' }}
   ></div>
</div>

and changing your second CSS selector like this

.radio__radio__after {
  content: "";
  width: 100%;
  height: 100%;
  display: block;
  border-radius: 50%;
  transform: scale(0);
  z-index: 9;
}

to allow the background color to be controlled by the style prop should work - although you might need to make some slight adjustments to the CSS or JSX.

Upvotes: 0

tharunoptimus
tharunoptimus

Reputation: 46

I'm new to React so, I'll provide the answer with Vannila JS.

The color change can be done in the following steps:

  • Set a root css variable :root{ --myColor: #545454; }
  • Set the DOM element's color to the css variable declared in the root like color: var(--myColor);
  • Since, you mentioned that the element is not loaded yet so there is not point in what color this myColor has because it has not effect except the variable itself because we will use it in JS to change it.
  • In JS, Get the Color from the API response and store it in a variable
  • Use document.documentElement to set the color of the css variable myColor with the color we get from the API
  • All the elements with the color of the CSS variable will also change.
  • The Element which gets loaded will have the color by then.

// I couldn't find a fake API response giving a Color, so this function mocks the API which gives the color string after 2 seconds.
let getColorFromAPI = new Promise((resolve) => {
    setTimeout(function() {
        resolve('#FFFFFF')
    }, 2000)
});


async function main() {
    console.log("The Existing Color is: ", getComputedStyle(document.documentElement).getPropertyValue('--mainColor'))
    console.log('Getting the Color from the API... ')
    let newColor = await getColorFromAPI // Get the color from API
    console.log('The New Color is: ', newColor)
    document.documentElement.style.setProperty('--mainColor', newColor) // Changing the color of the CSS variable
}

main()
:root {
    --mainColor: #545454;
}

.buttonElement {
    background-color: var(--mainColor);
}
<button class="buttonElement">See the Color of this button</button>

To Wrap things up:

  • The function gets the color from the API and we set the color using document.documentElement.style.setProperty

You can also create a dummy class with just the background-color and append it to the element since, Browser computes the style with the latest CSS style declaration.

Hope this helps.

Upvotes: 0

gyan.JS
gyan.JS

Reputation: 1

<!DOCTYPE html>
<html>

<head>
    <title>
        How to define colors as variables in CSS?
    </title>
    <style>
        :root {
            --primary-color: rgb(15, 157, 88);
            --secondary-color: rgb(255, 255, 255);
        }

        .first {
            width: 50%;
            padding: 40px 0px;
            margin: 10px 0px;
            text-align: center;

            /* Apply color using CSS var */
            background-color: var(--primary-color);
            color: var(--secondary-color);
        }

        .second {

            width: 50%;
            padding: 40px 0px;
            text-align: center;

            /* Apply color using CSS var */
            background-color: var(--primary-color);
            color: var(--secondary-color);
        }
    </style>
</head>

<body>
    <div class="first">
        <h1>Stackoverflow</h1>
    </div>

    <div class="second">
        <h1>gyan-js</h1>
    </div>
</body>

</html>

Upvotes: 0

Elron
Elron

Reputation: 1465

You can use CSS Custom Properties as variables for the colors, using the :root class:

:root {
  --brand-color: #f28b46;
}

.radio__radio {
  width: 24px;
  height: 24px;
  background-color: #d8d8d8;
  border-radius: 50%;
  box-sizing: border-box;
  padding: 6px;
  margin-right: 20px;
  z-index: 1;
}

.radio__radio::after {
  content: "";
  width: 100%;
  height: 100%;
  display: block;
  background: var(--brand-color);
  border-radius: 50%;
  // transform: scale(0);
  z-index: 9;
}
<div class="radio__radio"></div>

And when fetching the brand color from the API, create a style tag and update the :root brand color.

Note: the last :root variable will override any previous :root variable, so you need to make sure you create the <style> with the brand color after your initial CSS file.

:root {
  --brand-color: yellow; // will be overridden
}
:root {
  --brand-color: red; // that's the color that will show
}

I got the idea that you're using react, so you can do this like this:

const [brandColor, setBrandColor] = useState();

useEffect( () => {
    fetchBrandColorFromAPI().then(brandColor => setBrandColor(brandColor));
}, [])

And then in the renderer:

{brandColor && <style dangerouslySetInnerHTML={{ __html: ` :root {
    --brand-color: ${brandColor}
}`}} /> }

Upvotes: 7

Andrew Corrigan
Andrew Corrigan

Reputation: 1057

The issue is that you can't manipulate pseudo-elements in javascript; however, there are still a couple of options to manipulate them by knock-on effect.

Option 1: As A Haworth suggested, use a CSS variable.

Option 2: If you know there's only going to be a few different colours; then you could just toggle a class indicating which colour it should be. For instance, if you set the CSS up in a similar structure to this:

.radio__radio {
  width: 24px;
  height: 24px;
  background-color: #d8d8d8;
  border-radius: 50%;
  box-sizing: border-box;
  padding: 6px;
  margin-right: 20px;
  z-index: 1;
}

.radio__radio::after {
  content: "";
  width: 100%;
  height: 100%;
  display: block;
  border-radius: 50%;
  transform: scale(0);
  z-index: 9;
}

.radio__radio.green::after{
   background-color: #000066 /* Silly colour as an example */
}
.radio__radio.blue::after{
   background-color: #006600 /* Silly colour as an example */
}
.radio__radio.red::after{
   background-color: #660000 /* Silly colour as an example */
}

Then your javascript

var d = document.getElementsByClassName("radio__radio"); /* This way supports older browsers */
d.className += " otherclass";

Or if usimg jQuery

$('.radio__radio').addClass('green').removeClass('red').removeClass('blue');

There is no way I know of for you to directly inject a runtime variable from your API without using the javascript as a middle-man - there may be a way to do it with Blazor, but I haven't yet come across it.

Upvotes: 0

A Haworth
A Haworth

Reputation: 36512

While you cannot directly set the styling of a pseudo element in JS you can set a CSS variable and this can be picked up by the class setting for the pseudo element.

.radio__radio {
  width: 24px;
  height: 24px;
  background-color: #d8d8d8;
  border-radius: 50%;
  box-sizing: border-box;
  padding: 6px;
  margin-right: 20px;
  z-index: 1;
  --bg: #f28b46; /* ADDED for initial condition */
}

.radio__radio::after {
  content: "";
  width: 100%;
  height: 100%;
  display: block;
  background: var(--bg);
  border-radius: 50%;
  transform: scale(0);
  z-index: 9;
}

Then in your Javascript when you get a new background color:

document.querySelector('.radio__radio').style.setProperty('--bg', newvalue);

or of course select all such radio buttons and change for each one if that is what is required.

Upvotes: 7

Related Questions