Modify css react component with styled-component - reactjs

I am consuming some component from library which are not in my project repo. Since I am using styled-component to develop my own component. I want to do little modification on component which I am consuming from other library without touching there code base. Here is little example of what I am trying to achieve but none of following style is getting applied to CustomCom
UI Library
const CustomCom = ()=>{
return (
<div>Child</div>
);
}
My Repo
export default styled(CustomCom)`
height: 20px;
background: green;
`;

This is only possible if the component passes className to the DOM element, per the styled-components documentation
The styled method works perfectly on all of your own or any
third-party components, as long as they attach the passed className
prop to a DOM element.
https://www.styled-components.com/docs/basics#styling-any-components
Here's some sample code, which of course modifies the Library code, which I understand you can't do, but you could fork the library and do it if you want.
const CustomCom = ({className})=>{
return (
<div className={className}>Child</div>
);
}
class App extends Component {
render() {
const MyElem = styled(CustomCom)`
height: 20px;
background: green;
`
return (
<MyElem />
);
}
}

Try below
export const newCustom = styled(CustomCom)`
height: 20px;
background: green;
`;
Now use this custom component
<newCustom />
If you want to extend existing HTML tags you can do this:
export const newCustom = styled.div`
height: 20px;
background: green;
`;

Related

Conditional styled components effect all instances when nested

If i use a prop condition on the main component it will work per instance.
So for example if i have:
const Div = styled.div<Props>`
${(props) => {
return css`
${props.test && "border: 5px solid red;"};
`;
}}
`;
only components which have the test prop will have this ugly border :)
But if i use this same condition on a nested css rule like that:
const Div = styled.div<Props>`
${(props) => {
return css`
.tabletScreen & {
${props.test && "border: 5px solid red;"};
}
`;
}}
`;
All instances of this component will have this ugly border if one of the components has this test prop.
When inspect it i see that all instances of the component gets the same class generated, so the this:
.tabletScreen .sc-jcFjpl {
border: 5px solid red;
}
Is implemented to all instances.
But on the first case (when the condition is not nested) the component with the test prop will get another class so it won't override the others.
How can i fix this?
Use && instead of & and it'll be scoped to that stylistic instance of the component. Single ampersand refers to the "static component class".
More info here: https://styled-components.com/docs/basics#pseudoelements-pseudoselectors-and-nesting
import React from "react";
import { render } from "react-dom";
import styled, { css } from "styled-components";
import Wrapper from "./Wrapper";
import Title from "./Title";
// Render these styled components like normal react components.
// They will pass on all props and work
// like normal react components – except they're styled!
const Div = styled.div`
${(props) => {
return css`
.tabletScreen {
border: ${props.test && '5px solid red'};
}
`;
}}
`;
const App = () => (
<Wrapper>
<Div test>
Without Test
<div className="tabletScreen">TabletScreen</div>
</Div>
</Wrapper>
);
render(<App />, document.getElementById("root"));

Access props inside the styled component using MUI

I'm trying to create a custom button component using MUI on a React JS project. I've checked the docs and I discovered that I can do this using styled components. All worked well with the code presented below. The problem is that I want to create a more "customizable" component. I have inside my theme file 2 sets of colors (primary and secondary). The fact is that I want to create a button that is able to take a prop for this set of colors (primary / secondary).
import * as React from 'react';
import ButtonUnstyled, {
buttonUnstyledClasses,
ButtonUnstyledProps,
} from '#mui/core/ButtonUnstyled';
import { styled } from '#mui/system';
import { theme } from '../../theme';
const CustomButtonRoot = styled('button')(`
background-color: ${theme.palette[props.type].main};
padding: 15px 20px;
border-radius: 10px;
color: #fff;
`);
interface TodoButtonProps {
unstyledProps: ButtonUnstyledProps,
type?: 'primary' | 'secondary'
}
function CustomButton(props: TodoButtonProps) {
return <ButtonUnstyled {...props} component={CustomButtonRoot} />;
}
export default CustomButton
The question is: How I can include this prop inside the styled component code?
Pass a callback. In this callback the first argument is the props of the styled component. You can also use the style object instead of template string. More detail in this answer.
const CustomButtonRoot = styled("button")(
({ theme, myColor }) => `
padding: 15px 20px;
border-radius: 10px;
color: ${myColor};
`
);
<CustomButton myColor="red">abc</CustomButton>

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.

Styled-components with animate.css

I use styled-components in my project. Now I would like to implement some simple animations like animate.css
Is that possible to use react-animations (or similar library) with styled-components ?
It's a waste of time to implements animations like in animate.css again. Additionally I don't want to install anothers package as Aphrodite because I have styled-components already.
I've found an answer with code:
import React from 'react';
import styled, { keyframes } from 'styled-components';
import { fadeIn } from 'react-animations';
const fader = keyframes`${fadeIn}`;
// Create a <Title> react component that renders an <h1> which is
// centered, palevioletred and sized at 1.5em
const Title = styled.h1`
font-size: 1.5em;
text-align: center;
color: palevioletred;
animation: 1s ${fader} alternate infinite;
`;
// Create a <Wrapper> react component that renders a <section> with
// some padding and a papayawhip background
const Wrapper = styled.section`
padding: 4em;
background: papayawhip;
`;
export default () => {
// Render these styled components like normal react components. They will pass on all props and work
// like normal react components – except they're styled!
return (
<Wrapper>
<Title>Hello World, this is my first styled component!</Title>
</Wrapper>
);
}

Resources