How to convert a JSON style object to a CSS string?
Asked Answered
I

6

17

I wanted to set my element's style as such:

this.refs.element.style = {
    ...this.props.style,
    background: 'blue',
};

But apparently you can't use an object to set the ref's style. I have to use a CSS style string with ; separating the prop:values

I'm aware that most people would set style in the render function, but for performance reasons, I can't repeatedly re-render.

Imposture answered 20/7, 2017 at 5:5 Comment(0)
I
43

A performant answer is to map and join the Object.entries with semicolons:

const style = {
  ...this.props.style,
  background: 'blue',
};

const styleString = (
  Object.entries(style).map(([k, v]) => `${k}:${v}`).join(';')
);

It unwraps background:'blue', to background:blue; which works well for CSS


To replace any capital letter with dash lowercase letter

k = k.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`);
Imposture answered 20/7, 2017 at 5:9 Comment(7)
Be aware that properties like backgroundColor should be renamed to background-color, but apart from that, a good use of reduce()!Lise
@EricSellin good catch, fixed that with a .replace, should work but maybe there are edge casesImposture
but it wont work in IE because IE doesn't support Object.entries()Photoflash
This will be rather slow for large objects - you're doing n string concatenations, and each concatenation is on the order of the length of the strings. You'd probably want a map + join instead.Saval
Who needs IE support in 2021?Inwrap
I admit I don't really worry much about IE anymore, but it won't be officially retired until 2022; a reasonably good polyfill for Object.entries is here: #45850331Dissimilate
Does your answer support vendor prefixes?Amena
H
12

this solution works in IE and handles camelCase keys like backgroundColor

const style = {
    width: '1px',
    height: '1px',
    backgroundColor: 'red',
    transform: 'rotateZ(45deg)',
}
const styleToString = (style) => {
    return Object.keys(style).reduce((acc, key) => (
        acc + key.split(/(?=[A-Z])/).join('-').toLowerCase() + ':' + style[key] + ';'
    ), '');
};

console.log(styleToString(style));
// output - "width:1px;height:1px;background-color:red;transform:rotateZ(45deg);"
Heteromerous answered 24/4, 2020 at 14:33 Comment(1)
the styleToString function fit good to meTargett
C
4

Use https://www.npmjs.com/package/json-to-css. Note it will not add a semicolon to the last property to fix it you can beautify it with https://www.npmjs.com/package/cssbeautify Example


    const cssbeautify = require('cssbeautify')

    const Css = require('json-to-css')

    const json = {
        "h1": {
            "font-size": "18vw",
            "color": "#f00"
        },
        ".btn": {
            "font-size": "18vw",
            "color": "#f00"
        }
    }


    const r = Css.of(json)
    console.log(r)

    const beautified = cssbeautify(r, {
        autosemicolon: true
    })

    console.log(beautified)

Result


  console.log src/utils/playground/index.spec.ts:22 // json-to-css
    h1{font-size:18vw;color:#f00}
    .btn{font-size:18vw;color:#f00}

  console.log src/utils/playground/index.spec.ts:29 // cssbeautify
    h1 {
        font-size: 18vw;
        color: #f00;
    }
    
    .btn {
        font-size: 18vw;
        color: #f00;
    }
   
Cowgirl answered 19/11, 2020 at 11:28 Comment(0)
I
1

Adding to the great answer of @Artem Bochkarev

I'm adding a snippet to do the opposite conversion as well (string to object) which may come in handy to anyone stumbling here

const style = {
  width: '1px',
  height: '1px',
  backgroundColor: 'red',
  transform: 'rotateZ(45deg)',
};
const styleToString = (style) => {
  return Object.keys(style).reduce((acc, key) => (
    acc + key.split(/(?=[A-Z])/).join('-').toLowerCase() + ':' + style[key] + ';'
  ), '');
};
const stringToStyle = (style) => {
  const styles = {};
  style.split(';').forEach((s) => {
    const parts = s.split(':', 2);
    if (parts.length > 1) {
      styles[parts[0].trim().replace(/-([a-z])/ig, (_, l) => l.toUpperCase())] = parts[1].trim();
    }
  });
  return styles;
};

console.log(styleToString(style));
// output - "width:1px;height:1px;background-color:red;transform:rotateZ(45deg);"

console.log(stringToStyle(styleToString(style)));
Inwrap answered 4/8, 2021 at 15:59 Comment(0)
W
0

TL;DR: The problem is that you are overwriting the entire "style" property of the element and losing its prototype and methods. You must add your style object without change the entire property. If you want to apply an object-like style to a DOM element, just do:

Object.assign(this.refs.element.style, {
    background: 'blue',
    color: 'white',
    /** style properties:values goes here */
});

Explanation: The property "style" is an instance of the "CSSStyleDeclaration" interface. If you overwrite the interface it wont be a "CSSStyleDeclaration" anymore. It works when you set a string as value because javascript will pass the string directly to the element, without process anything.

CSSStyleDeclaration Reference Doc: https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration

If you want to do a test, go to your navigator > inspector > console and paste the code below:

const p1 = document.createElement('p');
p1.style = { color: 'blue' };

const p2 = document.createElement('p');
Object.assign(p2.style, { color: 'blue' });

console.log(p1);
console.log(p2);

The output will be:

<p style=""></p>
<p style="color: blue;"></p>
Whitlow answered 4/2, 2023 at 3:35 Comment(0)
S
-1

the css function in @material-ui/system can help you out check more info here

import React from 'react';
import styled, { ThemeProvider } from 'styled-components';
import NoSsr from '@material-ui/core/NoSsr';
import { createMuiTheme } from '@material-ui/core/styles';
import { compose, spacing, palette, css } from '@material-ui/system';

const Box = styled.div`
  ${css(
    compose(
      spacing,
      palette,
    ),
  )}
`;

const theme = createMuiTheme();

export default function CssProp() {
  return (
    <NoSsr>
      <ThemeProvider theme={theme}>
        <Box color="white" css={{ bgcolor: 'palevioletred', p: 1, textTransform: 'uppercase' }}>
          CssProp
        </Box>
      </ThemeProvider>
    </NoSsr>
  );
}
Sectarianize answered 26/3, 2020 at 6:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.