10

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

Chandler Bing
  • 410
  • 5
  • 25

7 Answers7

7

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.

A Haworth
  • 30,908
  • 4
  • 11
  • 14
  • The element here ```. radio__radio``` is undefined. I'm using react btw. The DOM is not loaded, I guess that simply means. – Chandler Bing Aug 19 '21 at 06:11
  • I see (I think!) - obviously you can't access that element until it is loaded, I'd assumed you were accessing it when some API gave you a new color to use. Perhaps you need to show us the relevant JS. – A Haworth Aug 19 '21 at 07:40
  • it is relevant. problem is clear, I'm getting a variable called ```brand_color``` from an API. it's giving a hex color and I want to use that hex color in my css. – Chandler Bing Aug 20 '21 at 10:47
  • Can you show the JS - the bit which gets the brand-color. Are you waiting for the DOM to load (or at least the bit which creates the element)? – A Haworth Aug 20 '21 at 11:30
  • The data I'm gettings is from ```getSettings``` an action call and dispatching in ```useEffect()``` when page loads. Really Sorry about my late responses – Chandler Bing Aug 22 '21 at 12:52
  • Hi, I don't understand why you can't use the JS to change the variable when you get the hex value. Can you show your code in your question please - the bit where you get a new hex value. – A Haworth Aug 29 '21 at 02:48
  • I might just point out that I think `document.querySelector` doesn't work with reactJS. You can utilize [`useRef`](https://reactjs.org/docs/hooks-reference.html#useref) hook. Refer this answer for [more](https://stackoverflow.com/questions/59198952/using-document-queryselector-in-react-should-i-use-refs-instead-how) – Rifky Niyas Aug 30 '21 at 11:23
7

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}
}`}} /> }
Elron
  • 1,235
  • 1
  • 13
  • 26
1

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>
ayushsoni1001
  • 76
  • 2
  • 4
0

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.

Andrew Corrigan
  • 1,017
  • 6
  • 23
0

<!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>
0

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.

0

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.

J.D. Sandifer
  • 814
  • 9
  • 20