How to apply multiple inline styles to a component as props? - css

I tried so many different things but nothing is working. It either breaks the application or only one style gets applied but not both at the same time. I have a parent component that passes some styles to a child and then the child itself has some local styles as well.
Parent component:
<CardSettings headline="Media accounts" size={{ flex: 1 }}></CardSettings>
Child component CardSettings.jsx:
const CardSettings = (props) => {
return (
<div style={({ background: '#fff' }, props.size)}>
<h2 style={styles.headline}>{props.headline}</h2>
{props.children}
</div>
)
}
What do I do wrong here? In this case flex: 1 gets applied but not background: #fff

Considering your size prop is an object you could use spread syntax to merge in those styles with the ones already inside that div:
<div style={{ background: '#fff', ...props.size }}>
<h2 style={styles.headline}>{props.headline}</h2>
{props.children}
</div>
Pre-ES6 Solution:
Alternatively you could try Object.assign as so:
<div style={Object.assign({{}, background: '#fff', props.size)}>
<h2 style={styles.headline}>{props.headline}</h2>
{props.children}
</div>

Related

Keeping two components the same height in all screen sizes (one with scroll, another without)

I have the following use case described in the image below.
I'm using Bootstrap 5 & React with Typescript
There are two components in a page called MainPage.tsx called Component1.tsx and Component2.tsx
Component2 has many more elements/content than Component1, so I want to put a scrollbar into it
I want Component1 to be the same height as Component2
On screen sizes with a width larger than >=768px (Boostrap .md breakpoint) I want the Component2 to be to the right of Component1. On mobile-like screens with widths >=576px (Bootstrap .sm breakpoint), I want Component2 to be right below Component1. In both modes, Component1 maintains its scrollbar.
However, what happens in my current code is that on mobile-like screens (when Component2 is below Component1), there is a big empty space between the two components.
My current code looks like this:
// MainPage Component
const MainPage = () => {
}
return (
<div className='d-flex flex-column flex-lg-row'>
<Component1 />
<Component2 />
</div>
)
}
export { MainPage }
// Component1.tsx
const Component1 = () => {
return (
<div className='flex-column flex-lg-row-auto w-100 w-lg-300px w-xl-400px mb-10 mb-lg-0'
style={{ overflow: 'scroll', overflowX: "hidden", height: "100vh" }}>
<div className='card card-flush'>
<div className='card-header pt-7'>
<OtherComponent1>
</div>
<div className='card-body pt-5'>
<div
className='scroll-y me-n5 pe-5 h-200px h-lg-auto'>
<OtherComponent2> />
</div>
</div>
</div>
</div>
)
}
export { Component1 }
// Component2.tsx
const Component2 = () => {
return (
<div className='flex-lg-row-fluid ms-lg-7 ms-xl-10'>
<div className='card' style={{ height: '100vh', overflowX: "hidden" }}>
<OtherComponent3/>
</div>
</div>
)
}
export { Component2}
However, what happens is that with this code, in boostrap .md screen-sizes it works as intended, but in bootstrap .sm screens-sizes, there's a big empty space between the two components. I suspect the problem is due to the "100vh" in Component1.tsx
What is the culprit and how can I solve it?

React animation inline styling

I am practicing React inline animation styling. I have made one toggle button, when user press button first time, I want pop up animated card from left to right. when user press button 2nd time it will close the card from right to left. I want to learn how the animation work inline react styling. Unfortunately I am unable to do that. Seems like React inline styling, transitions and translate does not work to me. This is the animation I want to do it. I shared my code in code-sandbox.
This is my code
import { useState } from "react";
export default function App() {
const [toggle, setToggle] = useState(false);
return (
<>
<button onClick={(): void => setToggle(!toggle)}>toogle button</button>
{toggle && (
<div
style={{
display: "flex",
zIndex: 1,
marginLeft: 170,
background: "red",
width: 200,
height: 300,
opacity: 1,
backgroundColor: "tomato",
transition: "opacity 5s"
}}
>
<p style={{ margin: "0px" }}>animation</p>
</div>
)}
</>
);
}
I don't think that this is a good idea, but here is one solution.
You can control everything.
import "./styles.css";
import { useState } from "react";
export default function App() {
const transitions = ["linear", "ease", "ease-in", "ease-out", "ease-in-out"];
const [opacity, setOpacity] = useState(0);
const [right, setRight] = useState(40);
const speed = 0.5;
return (
<>
<button
onClick={() => {
setOpacity(opacity ? 0 : 1);
setRight(prev => prev === 40 ? 20 : 40);
}}
>
toogle button
</button>
<div
style={{
display: "flex",
zIndex: 1,
marginLeft: 170,
background: "red",
width: 200,
height: 300,
opacity,
backgroundColor: "tomato",
transition: `all ${transitions[1]} ${speed}s`,
transform: `translateX(-${right}%)`
}}
>
<p style={{ margin: "0px" }}>animation</p>
</div>
)
</>
);
}
You could use the inlined styles, but you cannot achieve the desired behavior without the use of CSS or a third party library doing the animations for you.
I would recommend to check out this: https://www.w3schools.com/css/css3_animations.asp
Another problem that I see:
You are displaying the content only as soon as the "toggle" property is true, but for animations you need to have different states in your markup in order to transition to different states of animation.
E.g.
<div className="opening">
<div className="opened">
<div className="closing">
<div className="closed"> (or removed from DOM)
Then you can apply the CSS #keyframes to all different stages using the corresponding CSS selectors.
Or if you don't want to dig into CSS yourself. You can use e.g. this library to do the job: https://react-spring.dev/

Styled components, two layers of className - How would I apply style in component declaration?

I have created a Container component with component styles in next.js.
When I declare use of this container component throughout my site, I would like to add a className to it and subjectively style it depending on the context of its use.
Here is an example of my Container component:
const Container = (props) => (
<>
<div className="container">
{props.children}
</div>
<style jsx>{`
.container{
width: 100%;
max-width: 1200px;
margin: 0 auto;
}
`}</style>
</>
)
export default Container;
So, I want to give it a maximum width of 1200px, and centre it with auto margins. No problem, I have done that.
Now, I am planning to use this component in the header of my site. But in the case of the header, I would like the Container component to be a flexbox:
import Container from './Container'
const Header = (props) => (
<>
<header>
<Container className="header-col">
<div>
<h1>{props.title}</h1>
</div>
<nav>
<ul>
{/* Navigation items */}
</ul>
</nav>
</Container>
</header>
<style jsx>{`
.header-col{
display: flex;
justify-content: space-between;
}
`}</style>
</>
)
export default Header;
When I view the site, I noticed the flexbox style I specified for the Container component in the header is not present.
I was expecting the className to take effect, and allow me to add additional styles.
I believe this has something to do with it thinking that className is not a class name, rather props. But, I want to keep my code dry by creating style inheritance on components.
How could I do this?
Thanks for the help!
This is a job for styled components:
import React from "react";
import styled from "styled-components";
export default function App() {
return (
<>
<Container custom={"header"}>
<h1>Very fancy h1 with flex display</h1>
</Container>
<Container custom={"regular"}>
<h1>Non-fancy h1 with no flex display</h1>
</Container>
</>
);
}
const Container = styled.div`
display: ${(props) => (props.custom === "header" ? "flex" : "block")};
/* you can call your prop ^^^^^^ whatever you want,
just change it on the container element too*/
& h1 {
/* you can apply css to children like so */
font-family: ${(props) =>
props.custom === "header"
? '"Courier New", Courier, monospace'
: '"Arial Black", Gadget, sans-serif'};
}
`;
In the above, I've created a custom styled component that receives the custom prop and then conditionally changes the values you are looking to adjust. To make the changes more visible to the eye, I've also styled the font so you can see the immediate difference between the two <Container> elements.
For a solution that is more scalable (e.g., for different themes), use ThemeProvider:
import React from "react";
import styled, { ThemeProvider } from "styled-components";
export default function App() {
return (
<>
<ThemeProvider theme={ContainerHeader}>
<Container>
<h1>Very fancy h1 with flex display</h1>
</Container>
</ThemeProvider>
<Container theme={"regular"}>
<h1>Non-fancy h1 with no flex display</h1>
</Container>
</>
);
}
const Container = styled.div`
display: ${(props) => props.theme.display};
& h1 {
font-family: ${(props) => props.theme.h1Font};
}
`;
Container.defaultProps = {
theme: {
display: "block",
h1Font: '"Arial Black", Gadget, sans-serif'
}
};
const ContainerHeader = {
display: "flex",
h1Font: '"Courier New", Courier, monospace'
};
CodeSandbox: https://codesandbox.io/s/stack-conditional-styled-components-vmnpn?file=/src/App.js:0-773
I believe I have found the answer to my own question (I will still leave this question open for a couple more days just in case it can be improved).
In order to pass styles, you can add the "global" flag to the styled JSX and append additional classnames in the component with props.className.
Parent Container component using props.className:
const Container = (props) => (
<>
<div className={`container ${props.className}`}>
{props.children}
</div>
<style jsx>{`
.container{
width: 100%;
max-width: 1200px;
margin: 0 auto;
}
`}</style>
</>
)
export default Container;
Then, when you want to use that component, you can add additional styles with the global flag in the <style jsx>:
Container being used and styled even more in the header:
import Container from './Container';
const Header = (props) => (
<>
<header>
<Container className="header-col">
<div>
<h1>{props.title}</h1>
</div>
<nav>
<ul>
<li>Hello</li>
<li>There</li>
</ul>
</nav>
</Container>
</header>
<style jsx global>{`
.header-col{
display: flex;
justify-content: space-between;
}
`}</style>
</>
)
export default Header;
This is not 100% perfect though (but in my opinion it is still pretty good):
The global flag makes your styles global. So other components can use
these styles (I believe)
You need to make sure your components take in props.className to append additional classnames for this global style

Full height in React using flex

I can't find an answer for this, even though there are many flex themed questions.
I created a simple React app (npx create-react-app).
I then deleted App.css and set the contents of index.css to:
html, body, #root {
height: 100%;
margin: 0;
}
Next, in App.js I'm trying to have a full screen element using flex:
import React from 'react';
function App() {
return (
<div style={{ backgroundColor: 'blue', display: "flex", flex: 1 }}>
<div style={{ display: "flex", flexDirection: "column", flex: 1 }} />
</div>
);
}
But it just won't work. Why is the flex element not stretching?
The flex-grow works when there are other elements in the flex. It makes the element to grow x times in comparison to others.
wrt the solution you have implemented: inner div doesn't require display: flex and direction too. It will be inherited from the parent div.
To make the div take the full height. add height: 100vh to the parent div.
Let me know if this will solve the problem.
Thank you.
To achieve height of window you need to mention height: 100vh for parent tag like
class- .parent{height: 100vh}
object style - style={{height: '100vh'}}
import React from 'react'
function App() {
return (
<div style={{ backgroundColor: 'blue', display: "flex", height:'100vh' }}>
<div style={{ display: "flex", flexDirection: "column", flex: 1 }} >Hello world</div>
</div>
);
}

Set background of div using flex

i am trying to develop a movie portal using react js. I am trying to display the movie poster, and the movie details adjacent to it.
I am using flex, but am encountering an issue with the output. The movie details are being pushed to an extreme end, and i am unable to figure out the reason.
I am trying to get the "The Dark Knight" adjacent to the poster.
This is the output screenshot
my Js code is as follows,
dialogContent: (backgroundUrl) => ({
backgroundImage: `linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.6)), url(${backgroundUrl}) `,
backgroundSize: 'cover',
overflow: 'hidden',
backgroundRepeat: 'no-repeat',
backgroundSize: '100%',
height: '33%',
minHeight: 400,
color: 'white',
padding: 10
}),
poster: () => ({
padding:5,
width:'100%',
margin:"auto"
}),
text:() =>({
color:"white"
}),
main:() =>({
backgroundColor: "black",
display: "flex"
})
}
class MovieDisplay extends Component {
render() {
//console.log(this.props);
const {movie} = this.props.location.state.movie;
return (
<div style={styles.main()}>
< div style={styles.poster()}>
<img src={movie.poster_path} />
</div>
<div style={styles.dialogContent(movie.backdrop_path)}>
<h1 style={styles.text()}>{movie.original_title}</h1>
<h2 style={styles.text()}>{movie.popularity}</h2>
</div>
<div >
<h5 style={styles.text()}> more content would be updated soon</h5>
</div>
</div>
);
}
}
Can anyone help figure out the reason?
Thanks in advance.
The problem is with the poster style set to width of 100% and margin of 'auto'.
poster: () => ({
padding:5,
// width:'100%', <-- Try changing this by either removing it or setting to 'auto' or a smaller value
// margin:"auto" <-- Get rid of this
})
One solution would be to add another inside main container, this way you have better control over the poster and movie information spacing. You should also add some justification/alignment to your flex styling, otherwise the child elements will float to the ends of the flexed container (As seen in your example).
Add the below to your styles.
main:() =>({
backgroundColor: "black",
alignItems: 'center'
}),
/*add this style*/
innerMain: () =>({
display: "flex",
}),
And then in your MovieDisplay component, write this.
<div style={styles.main()}>
<div style={styles.innerMain()}>
...
<div style={{width: 100 + '%'}}>
<h5 style={styles.text()}> more content would be updated
soon
</h5>
</div>
</div>
<div>
Edit: I've added a codepen to demonstrate what these styles will accomplish. More styling (like for the poster image) might be required but this is the general layout of what you're looking for.
I also added a minWidth of 200 to the dialogContent and made the div containing more content... have a width of 100% to fill the remaining space.

Resources