Styled components: nested className selectors vs multiple styled components - reactjs

In general, are there any significant performance differences between using one of these approaches over the other?
When using styled components I've noticed two common approaches:
Have a styled parent component that uses className selectors to target child nodes for styling, and encapsulates those styles in the one place.
Have multiple styled components for each individual node that requires styling, independent of any parent styled components.
1 - nested selectors
const MyComponent = styled.div`
display: inline-block;
position: relative;
.MyChildComponent {
position: absolute;
background: red;
}
.MySubComponent {
background: yellow;
}
`
// In use
<MyComponent>
<span className="MyChildComponent>A goose!</span>
<button className="MySubComponent">Click bait</button>
</MyComponent>
2 - discrete components
const MyComponent = styled.div`
display: inline-block;
position: relative;
`
const MyChildComponent = styled.span`
position: absolute;
background: red;
`
const MySubComponent = styled.button`
background: yellow;
`
// In use
<MyComponent>
<MyChildComponent>A Goose!<MyChildComponent>
<MySubComponent>Click bait</MySubComponent>
<MyComponent>
Obviously there are situational reasons to mix and match these approaches, and I'm not taking into consideration use cases where a component may be re-used throughout a code base. I'm instead asking in the context of large chunks of markup that are unlikely to change or be shared.

Related

How to make Styled components generic to receive parameters?

I'm trying to use Styled Components with React FC. I want to display few details inside a div container, which all has the same stylings. Instead of writing hard coded such as Name: Height: Weight: etc. in the h-tags, can I do it in a more generic way to pass the text as parameter?
This is the way I have implemented, but I am thinking there should be some better way to do it. Like giving a parameter to the Styled component.
const CardContentContainer= styled.div`
margin: 4px;
padding: 4px;
text-align: left;
font-size: 14px;
`;
const CardContentDetails = styled.h3`
font-weight: normal;
color: #fff;
margin: 8px;
white-space: nowrap;
`;
this is the code inside the return:
return (
<CardContentContainer>
<CardContentDetails>
Name: {ItemDetails?.name}
</CardContentDetails>
<CardContentDetails>
Height:{ItemDetails?.height}
</CardContentDetails>
<CardContentDetails>
Weight:{ItemDetails?.weight}
</CardContentDetails>
</CardContentContainer>
);
You cant pass such props to Styled components because the main point of SC is to apply a custom style to that component. To make it receive some custom props, you have to wrap it inside another component like so...
const StyledTextField = styled(TextField)`
margin-bottom: 1rem;
width: 20em;
`;
const Comp: React.FC<{ title: string }> = ({ title }) => (
<StyledTextField>{title}</StyledTextField>
);
return (
<Comp title="some title" />

Reusing existing CSS in styled-component

We've a large project that exist of multiple styled components.
But for a next release and design update of that component we'll working together with a new partner that will deliver the styleguide and a CSS file that they are created for our client.
So I'm looking how I can re-use the styles of our partner in a styled component.
Do you think it's a good idea to do something like:
const PrimaryButton = styled(".btn-primary)``.
Instead of:
const PrimaryButton = styled.button``;
Actually, I can not find any working example, thus I think it's not possible... So, does someone know how I can do something like this?
Ehm, and for some reason I want to avoid to have something like this...
<PrimaryButton className="btn-primary"></PrimaryButton>
You can reuse styled components by extending the styles.
const Button = styled.button`
color: palevioletred;
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
// A new component based on Button, but with some override styles
const PrimaryButton = styled(Button)`
color: blue;
border-color: blue;
`;

utility classes in styled component react

hi I am using styled componant in react
const H4 = styled.h4`
font-size: 15px;
letter-spacing: 0.38px;
line-height: 1.33;
color: red;
padding: 20px;
`;
<H4>Small header</H4>
it will give exsact style in H4 tag. but how can I override this padding with utility classes like m-b-10 it will give margin-bottom:10px
something like this <H4 m-b-10>small header</H4>
same time I need to use this utility class whereever I want. in css I can simply write
m-b-10{margin-bottom:10px !important};
how can achieve this things on styled componenet?
One of the best solutions is to use https://styled-system.com/, it plays well with Styled Components and other libraries like Emotion and it offers what you need, to use utility-classes in the component definition.
Example:
import styled from 'styled-components'
import { color, space, fontSize } from 'styled-system'
// Set default styles and add styled-system functions to your component
const Box = styled.div`
/*defaut styles */
color: white;
font-size: 25px;
padding: 20px;
/* configurable properties */;
${color};
${space};
${fontSize};
`;
And to use it:
<Box bg="black" >
Lorem Ipsum
</Box>
<Box bg="black" color="green" fontSize="12px" p="10px">
Lorem Ipsum
</Box>
That code, will render this:
It also supports Media-Querys, Themes etc..
You can play with this CodeAndSandbox where it is been used with Styled Components https://codesandbox.io/s/styled-components-with-styled-system-njr17
You can use variables like
const m-b-10 = '20px';
const H4 = styled.h4`
padding: ${m-b-10};
`;
You can define such variables in a separate file and import them to styles components
You can define utility classes in the top component of your React tree. The example uses Gatsby.js, but you can easily adapt it for other React framework.
// src/components/layout.js
const GlobalStyles = createGlobalStyles`
html {
/* Put your CSS variables here*/
}
.m-b-10 {
margin-bottom: 10px;
}
`
Then make whatever defined in createGlobalStyles available for access in child components.
// src/components/layout.js
export default function Layout({ children }) {
return (
<React.Fragment>
<GlobalStyle />
{children}
</React.Fragment>
)
}
// src/pages.index.js
import Layout from "../components/layout"
const H4 = styled.h4`
font-size: 15px;
letter-spacing: 0.38px;
line-height: 1.33;
color: red;
padding: 20px;
`;
const IndexPage = () => {
return (
<Layout>
<H4 className="m-b-10" />
</Layout>
)
}

Passing in same prop to multiple styled components

I have 3 React Components that are all being passed the same prop isNewListingsHeader. I am using Styled Components for CSS styling. I'm wondering if there is a cleaner way of passing this prop into the 3 different styled components SortBarWrapper, SortOptionsWrapper, and SortOptionsWrapper so that I don't have to define isNewListingsHeader each time.
// Styled Components
const SortBarWrapper = styled.div`
position: relative;
${props => !props.isNewListingsHeader && `
height: 100px;
`}
`
const SortLineWrapper = styled.div`
width: 100%;
${props => !props.isNewListingsHeader && `
position: absolute;
bottom: 0;
`}
`
const SortOptionsWrapper = styled.div`
box-sizing: border-box;
${props => !props.isNewListingsHeader && `
padding-bottom: 24px;
padding-top: 32px;
`}
`
render () {
return (
<SortBarWrapper isNewListingsHeader={this.props.isNewListingsHeader}>
<SortLineWrapper isNewListingsHeader={this.props.isNewListingsHeader}>
<SortOptionsWrapper isNewListingsHeader={this.props.isNewListingsHeader}>
// Display Sort Options
</SortOptionsWrapper>
</SortLineWrapper>
</SortBarWrapper>
)
}
What you are doing is not incorrect but I can understand you wanting to DRY up your code. I am not going to say what is the "right" way because there is technically no correct way, just ways you prefer to do it based on your stack (for example, are you using Redux or any other state management?).
This medium post covers several methods of deep nesting components.
Explore that and pick which works for you. But for the sake of this conversation - you are doing it correctly and in the "React way."
We can use context api. Create a provider and Consumer. Wrap all the components inside the provider, Provider accepts a value prop and the data in this prop is available to all the child consumers. And can use them inside consumer.
“Why you should consider the new Context API in React? — A deep dive” by Mahesh Haldar https://link.medium.com/zrYj36RnhU

Styled components for colored tags

Styled components looks great, but I am having trouble organizing my components. My first venture with is a tag list, that automatically colors the tags. After some trial I came up with a component that can be used like this:
// An array of tags. The string hashes determine the color
<ColorTags tags={post.frontmatter.tags} inline/>
It is implemented as follows:
components/
ColorTags // functional component
ColorTagLI // styled component
ColorTagUL // styled component
With:
// ColorTags
import ColorTagLI from './ColorTagLI'
import ColorTagUL from './ColorTagUL'
export default ({tags, inline}) =>
<ColorTagUL>
{tags.map( tag =>
<ColorTagLI key={tag} colorString={tag} inline>
<Link to="/">
{tag}
</Link>
</ColorTagLI>
)}
</ColorTagUL>
// ColorTagUL
export default styled.ul`
list-style-type: none;
margin: 0;
padding: 0;
`
// ColorTagLI
const colorHash = new ColorHash({lightness: [0.4, 0.5, 0.6]});
const hslColor = cString => {
const [h, s, l] = colorHash.hsl(cString)
return `hsl(${h}, ${s*100}%, ${l*100}%)`
}
export default styled.li`
color: white;
background-color: ${props => hslColor(props.colorString)};
display: ${props => props.inline ? 'inline-block' : 'block'};
padding: 0.25rem 0.5rem;
margin: 0.25rem;
> a { text-decoration: none; color: white; }
`
Some questions I have:
What's a good way to discern between styled and regular components? I
decided on appending the HTML tag to the styled components, since
they are always tied to that.
Is it not a problem to have the Link tag inside a Styled component?
Should the ColorTag components be in a folder of themselves? Because they are tightly coupled.
Is using theinline prop a smart way to switch between configurations? It may
result in a lot of conditional statements for margins, padding and
media queries... Perhaps better make two different components?
You can use utility function isStyledComponent.
Why would it be a problem to have a Link component inside styled component?
Matter of opinion, if you believe they are tightly coupled you can create /ColorTag directory with index.js file that exports only what should be exposed.
Yes it may result in a lot of conditional statements, that's why you can extend styles on styled components.
I hope I understood you right and my answers are clear.

Resources