I once found myself having to copy some HTML elements and convert into JSX. The elements were accompanied with inline styles that React was evidently not happy with 😡.
import React from "react"; | |
const ExampleComponent = () => { | |
return ( | |
<div style="margin: 32px; display: flex; flex-direction: column; align-items: center;"> | |
{new Array(10).fill().map((_, index) => ( | |
<div key={index}> | |
<h3>Item {index + 1}</h3> | |
<p> | |
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Possimus | |
sequi deserunt deleniti sapiente atque assumenda facere vero amet, | |
quidem modi mollitia dignissimos ipsa alias harum ipsam culpa iste | |
consequatur corporis. | |
</p> | |
</div> | |
))} | |
</div> | |
); | |
}; | |
export default ExampleComponent; |
React expects an object, with property names unhyphenated but in camel case, to be passed into the style attribute. I could do it manually but it gets boring and error prone with time. So I decided to write a Javascript function that automates the conversion.
const formatStringToCamelCase = str => { | |
const splitted = str.split("-"); | |
if (splitted.length === 1) return splitted[0]; | |
return ( | |
splitted[0] + | |
splitted | |
.slice(1) | |
.map(word => word[0].toUpperCase() + word.slice(1)) | |
.join("") | |
); | |
}; | |
export const getStyleObjectFromString = str => { | |
const style = {}; | |
str.split(";").forEach(el => { | |
const [property, value] = el.split(":"); | |
if (!property) return; | |
const formattedProperty = formatStringToCamelCase(property.trim()); | |
style[formattedProperty] = value.trim(); | |
}); | |
return style; | |
}; |
Given a string "display: flex; flex-direction: column; align-items: center; -webkit-align-items: center"
passed into getStyleObjectFromString
as an argument, an empty object literal is created. On line 15 the string is split around all semicolons resulting in an array of strings ```["display:
flex", "flex-direction: column", "align-items: center", "-webkit-align-items: center", ""]
The array of string is then looped over using the Array's `forEach` method. `forEach` takes a callback function that receives each element of the array per iteration as argument. Our callback function splits each element around the colon (":"), separating the CSS property name and value. It assigns these to `property` and `value` variable names.
Given `"display: flex"`, property will equal `"display"` while value equals `" flex"`. Given an empty string (the last element in the array), property will equal `""` while value equals `undefined` (both falsy values).
On line 17, the function returns if `property` is falsy. On line 19, the trimmed property name - cuz "edge cases" :wink: - is passed into `formatStringToCamelCase` which splits the string parameter around every occurence of an hyphen ("-") then changes the first letter in every other word besides the first to an uppercase letter. It then joins every word together. If `"align-items"` was passed, this operation will give `"alignItems"`.
The result from `formatStringToCamelCase` is our property name, in the right format, to be used in our style object to point to the trimmed `value` string.
At the end of the day, `"display: flex; flex-direction: column; align-items: center; align-items: center; -webkit-align-items: center"` gives `{ display: "flex", flexDirection: "column", alignItems: "center", WebkitAlignItems: "center" }`.
You can check out the demo on [Code Sandbox](https://codesandbox.io/s/react-inline-css-to-style-object-drc0r)
Top comments (3)
There's a far simpler way to do this while leveraging the browser to do all the work for us:
Thanks for this! just had to convert a html template to react and this was a timesaver!
Might be good to tweak it so it allows whitespace at the end. Most strings would always be: style=" color: red; " with white space after the last ; because of auto-formatting and I had to keep deleting it. Looking back, probably would have been faster to tweak the code myself, but I thought it was only a few that had that issue, not most of them.
I'm glad it helped. Thanks for the suggestion, I'll work on it.