Combining CSS and custom CSS properties inline on a react component - javascript

I need to pass custom CSS properties inline to a React component (Google Model Viewer in this instance),combined with more run-of-the-mill styles (background width, height etc.). There's quite a lot of questions on using custom properties inline with react, but I couldn't see one for specifically combing the properties with other styles.
I have the styles here, with the commented out style being an example of the custom property.
const styles = {
width: "100%",
height: "100%",
background: this.props.background,
// "--progress-bar-height": this.props.progressBarHeight
};
The const gets passed into rendering the component:
return (
<model-viewer
style={styles}
</model-viewer>
How do I combine the usual inline styles with the custom properties to add inline?
I tried adding it as a variable (as seen elsewhere on SO):
const progressBarHeight={ "--progress-bar-height": this.props.progressBarHeight };
But wasn't sure how to combine that with the {styles} . I tried longhand declaring each style and adding the variable to the list, but that didnt work either:
style={{ background: styles.background, width: styles.width, height: styles.height, progressBarHeight }}
Any tips?

You can simply use object spreading for this
style={{...styles, ...progressBarHeight }} // progressBarHeight = { "--customrvar" : '1px'}
Here's a working demo

Shouldn't a simple object map work?
Here is a sample code -
const styles = {
width: "100%",
height: "100%",
background: "this.props.background",
//"--progress-bar-height": "black"
};
const props = {
"--progress-bar-height": "white"
}
for(let i in props)
{
styles[i] = props[i];
}
for(let i in styles)
{
console.log(styles[i]);
}
And then the resulting combined style goes into props of your component.

Related

TypeScript / Styled component passing image as props

I have the following code below which is meant to show the
"NoBillsLaptopPNG.src" on the screen, but no image is being rendered.
The images are being imported fine, but not sure why the image is not being displayed.
import NoBillsMobilePNG from "../../public/assets/quotes/no-bills-mobile.png"
import NoBillsLaptopPNG from "../../public/assets/quotes/no-bills-laptop.png"
export const NoBillsSummary = () => {
return <div>
<TestImg
NoBillsMobilePNG={NoBillsMobilePNG.src}
NoBillsLaptopPNG={NoBillsLaptopPNG.src}
></TestImg>
</div>;
};
const TestImg = styled.img<{
NoBillsMobilePNG: string;
NoBillsLaptopPNG: string;
}>`
// the reason the img is being passed in as props as media query will later be added to switch between images
src: url(${(NoBillsLaptopPNG) => NoBillsLaptopPNG.src});
width : 126.07px;
height : 107.59px;
margin-top: 2px;
`;
when you use the TestImg component, you are passing src as props to NoBillsLaptopPNG.
It would be better to name props as NoBillsLaptopPngSrc.
When you style TestImg, the NoBillsLaptopPNG input parameter is already src. Therefore, it makes no sense to refer to its src field again.
try this
src: url(${(NoBillsLaptopPNG) => NoBillsLaptopPNG});
With styled-components, when you interpolate a function within your style, styled-components will call that function with the entire props of the component.
Therefore, you have to either refer to a specific member, or destructure it, like for a usual React Function Component.
Next, it is normally not possible to change the src attribute of an <img> through style only (CSS). However, it is still possible to change its content.
Finally, as implied by #forlift's answer, you already pass just the .src value to the prop, so there is no need to re-access it again.
const TestImg = styled.img<{
NoBillsMobilePNG: string;
NoBillsLaptopPNG: string;
}>`
// Notice the destructuring of the props
content: url(${({ NoBillsLaptopPNG }) => NoBillsLaptopPNG});
width : "226.07px";
height : "207.59px";
margin-top: "2px";
`;

Prevent React from rendering inline styles

const Component = () => <CustomButton color="highlight">Click me</CustomButton>;
const colors = { highlight: "#123456" };
export const CustomButton = styled(Button)`
${({ props }) =>
color: ${colors[props.color]}};
`;
How can I prevent React form rendering "color="highlight" as an inline style in line 1?
I sometimes use CSS named properties to use them within my CSS in JS library as props (styled components in this case).
React renders this HTML, though:
color="highlight" is not valid HTML and displays no color.
Since color="highlight is rendered as an inline style, my styled components stylesheets are not working anymore and the styles are broken.
The correct output should be
// no inline styles applied
<button class="sc-crzoAe dV0xyD sc-cTJkRt jDcPXG" />
// corresponding style sheet class
.sc-crzoAe {
color: #123456;
}
Keep in mind that React handles some CSS properties like width, height as a shortcut to style={{ width: "100%", height: "50%" }}. That's where the behaviour comes from I think.
One idea I had was to just rename the prop, but it would be nice to have a prop called color to take care of the color.
The correct way to set color is this:
export const CustomButton = styled(Button)`
color: => ${(props) => colors[props.color]};
`
An example can be shown here

How do I style a div inside a component without passing props to that component (I'm using a package)

I'm using the react-scrollbar package to render a scrollbar for my my content. What I also want is a arrow button that, on click, moves to a certain scrollbar area. The problem is, I'm trying to style (marginTop) a class inside my component.
This is my attempt:
// MY COMPONENT
scrollToNextUpload = () => {
const NextUpload = 400
this.setState({ marginTop : this.state.marginTop + NextUpload }, () => document.getElementsByClassName('scrollarea-content')[0].style.marginTop = "'" + this.state.marginTop + "px'")
}
// MY RENDER
render () {
<ScrollArea>
// my content
<div onClick={this.scrollToNext}></div>
</ScrollArea>
}
What is actually rendered
<div class='scrollarea'>
<div class='scrollarea-content'>
// my content
<div onClick={this.scrollToNext}></div>
</div>
</div>
What I want
To make my area with the scrollbar scroll, I have to add a marginTop style to the 'scrollarea-content'. I could do this by passing props to the < ScrollArea > and then use them inside the installed package; but I'm trying to avoid altering the original package content.Also, is there another way how I could scroll by click and is there someone else who's experienced with that NPM Package?
Most libraries give props to apply style to child components, in this library you can pass a className to the contentClassName or use inline style in contentStyle prop :
<ScrollArea contentStyle={{ marginTop: 10 }}>
An another way is to write css to add style to the scrollarea-content class.
In a .css file :
.scrollarea-content {
margin-top: 10px;
}
Edit: In your case you can programatically change the marginTop style by using the props like this :
scrollToNextUpload = () => {
const NextUpload = 400;
this.setState(prevState => ({ marginTop : prevState.marginTop + NextUpload }));
}
render () {
<ScrollArea contentStyle={{ marginTop: this.state.marginTop }}>
// my content
<div onClick={this.scrollToNext}></div>
</ScrollArea>
}
Note the use of a functional setState to prevent inconsistencies when next state value depends on the previous state.

How can I pass props to base component in styled-component?

As an example, let's say I've a component that can take in props like this:
const testComponent = (props: {isBold: boolean}) => {
if(props.isBold)
return <strong><div>hello</div></strong>
return <div>hello</div>
}
In this case, my example component that can take in props and the result depends on the props given to it.
Now, if I extend this component in styled-components, how can I pass my props into the base component? The idea is something like this:
const styledTestComponent = styled(testComponent({isBold: true}))`
width: 100%;
opacity: 0.5
/* etc etc... */
`
Well, obviously not going to work. This part will fail: styled(testComponent({isBold: true}))
But the idea is that what I want to do is to use CSS to style a particular instance of a component. So in that case, I will need to pass a pre-defined props to the base component, testComponent.
How can I achieve this?
Update:
I've come up with a quick example to illustrate the issue. The code below attempts to style a react component MyCustomImage as a styled-component StyledMyCustomImage. When this is run, you can see that StyledMyCustomImage does render itself as MyCustomImage. However, the CSS styles are not applied.
const MyCustomImage = props => (
<img
src={`https://dummyimage.com/${props.width}x${props.height}/619639/000000`}
/>
);
const StyledMyCustomImage = styled(MyCustomImage)`
border: 2px dotted red;
`;
function App() {
return (
<div className="App">
<h3>Test passing props from styled component to base component</h3>
<StyledMyCustomImage width="600" height="400" />
</div>
);
}
I've created a sandbox for this demo: https://codesandbox.io/s/k21462vjr5
Update 2:
Oh! Thanks to #SteveHolgado's answer, I've gotten it to work! I didn't know styled component will pass the CSS as a prop to its base component! Here's the code after adding in the class name for future reference:
const MyCustomImage = props => (
<img
src={`https://dummyimage.com/${props.width}x${props.height}/619639/000000`}
className={props.className}
/>
);
const StyledMyCustomImage = styled(MyCustomImage)`
border: 2px dotted red;
`;
The sadnbox of the working demo: https://codesandbox.io/s/j4mk0n8xkw
Try this, it should work
const StyledTestComponent = styled(testComponent)`
width: 100%;
opacity: 0.5
/* etc etc... */
`
and pass the prop to instance in this way.
<StyledTestComponent isBold />
Feedbacks are welcome. I have not checked it working, but feels it will work
Note: I checked and it's working. Should work for you.
When you use the styled function like that, your wrapped component will get passed a prop called className, which you need to apply to the element that you want the styles to affect:
const testComponent = (props) => {
return <div className={props.className}>hello</div>
}
You will have access to all props in your styles, which you can use like this:
const styledTestComponent = styled(testComponent)`
width: 100%;
opacity: 0.5;
font-weight: ${props => props.isBold ? "bold" : "normal"};
/* etc etc... */
`

React: style all elements with inline styles

I want to make all of my elements border-box. I want to do this:
* {
box-sizing: border-box;
}
How is that possible to do in with React's inline styles? I don't want to write that rule in each component...
This is ill-advised since CSS will be much more efficient, manageable, and flexible. But if you REALLY wanted to have global inline React styles, I might do it like this:
var App = React.createClass({
globalStyle: {
boxSizing: "border-box"
},
render() {
return (
<div>
<MyComponent globalStyle={this.globalStyle} />
</div>
);
}
});
var MyComponent = React.createClass({
style: {
border: "1px solid black"
},
render() {
return (
<div style={Object.assign({}, this.props.globalStyle, this.style)}></div>
);
}
});
Basically pass global style down to components as props and have them incorporate it there.
Note that Object.assign()'s first parameter is a new empty object (so that we don't accidentally mutate our others) and that this.style comes last (so that it overrides any global styles.)
If you wanted the global style to change, you'd do it with React's component state instead and use getInitialState etc. I suppose that might actually be the only reason you'd want to do it this way.

Categories