styled-components: styled custom component, with some props - reactjs

I have a <Header /> component, which takes a size prop. I want to take a Header with a size prop, and additionally style it with styled-components.
Something like the following, but this obviously doesn't work.
const MyHeader = styled(<Header size="huge />)`
margin-top: 2rem;
`
Any ideas how to achieve that?

You can do:
const MyHeader = styled(Header)({ ... });
For example:
const MyHeader = styled(Header)`
color: red;
`
Or if you want:
const Temp = () => <Header size="huge" />;
const MyHeader = styled(Header)({ ... });

Related

styled-components: style based on non-styled class parent

Let's say I have this:
const Child = styled.button`
background-color: grey;
`;
<div className="some-non-styled-class">
<Child>Hello World</Child>
</div>;
<div className="some-other-non-styled-class">
<Child>Hello World</Child>
</div>;
How can I style Child so it's "red" when under some-non-styled-class and "blue" when it's under some-other-non-styled-class?
I'm aware of the ability to refer to other styled-components, but I have a use case where I need to change styling based on an existing library with static class names.
You could try something like this then:
export const Child = () => {
const [parentClass, setParentClass] = useState("")
useEffect(() => {
const currentClass = document.querySelector(".childComp").parentElement.className
setParentClass(currentClass)
},[])
return (<MyStyledComponent className="childComp" parentClassName={parentClass}>
{children}
</MyStyledComponent>)
}

How to use styled from react-emotion with HighchartsReact?

I want to wrap HighchartsReact with HighChartWrapper using styled from react-emotion.
Below is the pseudo-code that I am trying.
import HighchartsReact from 'highcharts-react-official';
import styled from 'react-emotion';
const HighChartWrapper = styled(HighchartsReact)`
/* some styles here */
.highcharts-background {
fill: white !important;
}
`;
<HighChartWrapper highcharts={Highcharts} options={chartData} />
The styles are not working. I am aware that styled can style any component as long as it accepts a className prop.
So does anyone has a working example or a workaround for this?
You can wrap your chart component and pass className prop by containerProps, for example:
const Chart = (props) => {
const [options] = useState({
...
});
return (
<HighchartsReact
highcharts={Highcharts}
options={options}
containerProps={{ className: props.className }}
/>;
);
};
const HighChartWrapper = styled(Chart)`
/* some styles here */
.highcharts-plot-border {
fill: black !important;
}
`;
Live demo: https://codesandbox.io/s/highcharts-react-demo-vosjm?file=/demo.jsx
Docs: https://github.com/highcharts/highcharts-react#options-details

how to change image src using props with styled component and react

I want to reuse my component for multiple pages.
so, I have to change img src in styled.img component as passing props.
is it possible to change image src on styled component ?
I applied my code like below.
it's not working..
//logic
import Myimg from './img/icon_my';
const OngoingLists = ({ ...props }) => {
return (
<ListsOutWrap>
<ProgramListWrap {...props}>
<IconWrap {...props} >
<MyIcon {...props} />
</IconWrap>
</<ProgramListWrap>
</ListsOutWrap>
);
}
// styled component
const MyIcon = styled.img.attrs({
src: props => props.Img || { Myimg },
})`
width: 100%;
`;
I tried like above, any image doesn't show...even default img file doesn't show..
how can I change src file by using props ??
should I use background-image ?
thanks for ur help in advance ! :)
Styled components are still just react components, and you can simply provide a default prop value in the case a src prop isn't passed when used.
import Myimg from './img/icon_my';
const MyIcon = styled.img`
width: 100%;
`;
MyIcon.defaultProps = {
src: Myimg,
};
Usage:
<MyIcon /> // uses default Myimg
<MyIcon src="/path/to/sourceImage" /> // uses "/path/to/sourceImage"
BTW Correct attrs format to accept props would be to define a function taking props and returning an object:
const MyIcon = styled.img.attrs(props => ({
src: props.Img || Myimg,
}))`
width: 100px;
`;

How do i use styled components with dynamic imports

I am trying to find a way to dynamically import an svg Icon that inherits some standard styling. I havn't see anyone else writing about this... so i think i am on the wrong track.
I have tried creating an SVG wrapper in styled components but that gives me a nest of svg > svg > path
I'm not sure if this is the right idea.
I want to stay away from using inline styles in case of specificity issues later.
The SVG Icon code <-- using Create React App i am exporting the svg as a default react component
export { ReactComponent as default } from './logo.svg';
My Icon code <-- the styled.svg is something i would like to merge with the DynamicIcon... is there a way to do something like DynamicIcon as TestStyle? <-- in the documentation the as is used to change the tag type so i don't think this is right?
const TestStyle = styled.svg`
height: 1rem;
width: 1rem;
display: inline-block;
`
const Icon: React.FC<IconProps> = ({ name }: IconProps): React.ReactElement => {
const DynamicIcon = lazy((): Promise<any> => import(`../../assets/icons/${name}.tsx`));
return (
<Suspense fallback={<div>Loading ...</div>}>
<DynamicIcon />
</Suspense>
);
};
The import is working and displaying but i would like to have the component as a styled component, this will give me access to themeing and dynamically changing the SVG style with props.
ℹ - My TypeScript foo is weak so will be using vanilla JS below
You can simply wrap the dynamically loaded component with styled(DynamicIcon).
Reference: Extending Styles documentation
// Instead of 👇
// const TestStyle = styled.svg`
// height: ${props => props.size};
// width: ${props => props.size};
// display: inline-block;
// `;
const Icon = ({ name, iconSize }) => {
const DynamicIcon = lazy(() => import(`./icons/${name}.jsx`));
// ... 👇 Wrap the dynamically loaded component in `styled()`.
const StyledIcon = styled(DynamicIcon)`
height: ${props => props.size}px;
width: ${props => props.size}px;
display: inline-block;
`;
return (
<Suspense fallback={<div>Loading ...</div>}>
<StyledIcon size={iconSize} />
</Suspense>
);
};
⚠ 🔥
But be aware that the above usage of using prop.size is not a good idea as it creates a multiple classes per each width/height.
(I was trying to get around it with .attrs but couldn't get it working but I find it outside the scope of this question and leave that to you 😉)
Check out the forked demo here.
And here is how the logo looks wrapped in styled component

how to pass multiple classNames to inner children with emotion js

I want to split the components into baseUI one and styled one:
eg.
MyComponent.jsx
export default class MyComponent extends React.Component {
...
...
render() {
const { wrapperClassName, className, childClassName } = this.props;
return (
<div className={wrapperClassName>
<div className={className />
<div className={childClassName} />
</div>
)
}
}
StyledMyComponent.jsx
import styled from 'react-emotion'
const StyledMyComponent = styled(MyComponent)(
...
...
)
export default StyledMyComponent
however anything I put to the styled function's argument they will go to the className only, is there a way I specify which props goes to which className?
also can I do something like sass/less with children selector?
hypothetically something like this:
const classes = css`
color: red;
span { // this works
color: black;
}
.childClassName { // this doesn't work
color: green;
}
`
<MyComponent className={classes} />
No you can't.
What you can do, is create specific components for the underlying div. This is how I make my components:
const MyComponentStyle = styled('div')....;
const MySecondComponentStyle = styled('div')...;
const MyThirdStyle = styled('div')...;
const MyComponent = ({ wrapperClassName, childClassName, className }) =>
<MyComponentStyle className={wrapperClassName}>
<MySecondComponentStyle className={className} />
<MyThirdStyle className={childClassName} />
</MyComponentStyle>
)
}
}
Conditionally styling the element and its children based on class names
You can conditionally change the styling of stuff below the main component based on its classes.
Taking your example:
const Something = () => (
<MyComponent className={classes}>
<div className="childClassName">child</div>
<div className="otherChildClassName">child</div>
</MyComponent>
You can style the children like so:
const classes = css`
color: red;
span {
color: black;
}
& .childClassName {
color: green;
}
`
note the & character. It essentially means "this class". So & .childClassName means "childrens of this element with class childClassName.
You could also use &.someClassName (note the lack of space), which would mean: "this element when it also has a class named someClassName.

Resources