I believe what the documentation is saying is that you should avoid including your styles inside of the rendering component:
DO THIS
const StyledWrapper = styled.div`
/* ... */
`
const Wrapper = ({ message }) => {
return <StyledWrapper>{message}</StyledWrapper>
}
INSTEAD OF THIS
const Wrapper = ({ message }) => {
// WARNING: THIS IS VERY VERY BAD AND SLOW, DO NOT DO THIS!!!
const StyledWrapper = styled.div`
/* ... */
`
return <StyledWrapper>{message}</StyledWrapper>
}
Because what happens is when the component's Props changes, then the component will re-render and the style will regenerate. Therefore it makes sense to keep it separate.
So if you read further on to the Adapting based on props section, they explain this:
const Button = styled.button`
/* Adapt the colours based on primary prop */
background: ${props => props.primary ? "palevioletred" : "white"};
color: ${props => props.primary ? "white" : "palevioletred"};
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
// class X extends React.Component {
// ...
render(
<div>
<Button>Normal</Button>
<Button primary>Primary</Button>
</div>
);
// }
this works because when you use the Button component in class X, it will know the props of class X without you having to tell it anything.
For your scenario, I imagine the solution would be simply:
const TabWrapper = styled.li`
display: flex;
align-items: center;
justify-content: center;
padding: 100px;
margin: 1px;
font-size: 3em;
color: ${props => (props.isSelected ? `white` : `black`)};
background-color: ${props => (props.isSelected ? `black` : `#C4C4C4`)};
cursor: ${props => (props.isSelected ? 'default' : `pointer`)};
`;
const Tab = ({ onClick, isSelected, children }) => {
return <TabWrapper onClick={onClick}>{children}</TabWrapper>
}
const X = <Tab onClick={() => console.log('clicked')} isSelected>Some Children</Tab>
I haven't tested this at all, so please feel free to try it out and let me know if it works for you or whatever worked for you!
Answer from dropbeardan on Stack OverflowI believe what the documentation is saying is that you should avoid including your styles inside of the rendering component:
DO THIS
const StyledWrapper = styled.div`
/* ... */
`
const Wrapper = ({ message }) => {
return <StyledWrapper>{message}</StyledWrapper>
}
INSTEAD OF THIS
const Wrapper = ({ message }) => {
// WARNING: THIS IS VERY VERY BAD AND SLOW, DO NOT DO THIS!!!
const StyledWrapper = styled.div`
/* ... */
`
return <StyledWrapper>{message}</StyledWrapper>
}
Because what happens is when the component's Props changes, then the component will re-render and the style will regenerate. Therefore it makes sense to keep it separate.
So if you read further on to the Adapting based on props section, they explain this:
const Button = styled.button`
/* Adapt the colours based on primary prop */
background: ${props => props.primary ? "palevioletred" : "white"};
color: ${props => props.primary ? "white" : "palevioletred"};
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
// class X extends React.Component {
// ...
render(
<div>
<Button>Normal</Button>
<Button primary>Primary</Button>
</div>
);
// }
this works because when you use the Button component in class X, it will know the props of class X without you having to tell it anything.
For your scenario, I imagine the solution would be simply:
const TabWrapper = styled.li`
display: flex;
align-items: center;
justify-content: center;
padding: 100px;
margin: 1px;
font-size: 3em;
color: ${props => (props.isSelected ? `white` : `black`)};
background-color: ${props => (props.isSelected ? `black` : `#C4C4C4`)};
cursor: ${props => (props.isSelected ? 'default' : `pointer`)};
`;
const Tab = ({ onClick, isSelected, children }) => {
return <TabWrapper onClick={onClick}>{children}</TabWrapper>
}
const X = <Tab onClick={() => console.log('clicked')} isSelected>Some Children</Tab>
I haven't tested this at all, so please feel free to try it out and let me know if it works for you or whatever worked for you!
You can pass an argument with Typescript as follows:
<StyledPaper open={open} />
...
const StyledPaper = styled(Paper)<{ open: boolean }>`
top: ${p => (p.open ? 0 : 100)}%;
`;
`as` prop of styled components in TypeScript
When you are working with Styled Components, do you use this?
Videos
I am trying to do this:
import React from 'react'
import styled, { CSSProperties, useTheme } from 'styled-components'
import { Theme } from './styles'
import useProps from './useProps'
export type BasicInputPropsType<T> = T | Array<T>
export type FactoryStyledPropsType = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
styledProps: any
}
export type InputPropsFunctionType<I, T> = (props: I) => T
export type InputPropsType<T, I> = T extends Function
? InputPropsFunctionType<I, T>
: T
export default function FactoryFactory<T>(
as: string,
serializer: (theme: Theme, props: T) => CSSProperties,
) {
return function Factory<I>(inputProps: InputPropsType<T, I>) {
const isPropsFunction = typeof inputProps === 'function'
const Styled = styled.div<FactoryStyledPropsType>(
props => props.styledProps,
)
function Component(props: I) {
const actualProps = isPropsFunction
? (inputProps as InputPropsFunctionType<I, T>)(props)
: props
const theme = useTheme()
const { styledProps, elementProps } = useProps(
actualProps,
theme,
serializer,
)
return (
<Styled
{...elementProps}
styledProps={styledProps}
/>
)
}
Component.toString = Styled.toString
return Component
}
}Essentially that styledProps, it should return what the styled component expects, but I can't figure out how to type it. I am looking at this type definition:
export interface ThemedStyledFunctionBase<
C extends keyof JSX.IntrinsicElements | React.ComponentType<any>,
T extends object,
O extends object = {},
A extends keyof any = never
> {
(first: TemplateStringsArray): StyledComponent<C, T, O, A>;
(
first:
| TemplateStringsArray
| CSSObject
| InterpolationFunction<ThemedStyledProps<StyledComponentPropsWithRef<C> & O, T>>,
...rest: Array<Interpolation<ThemedStyledProps<StyledComponentPropsWithRef<C> & O, T>>>
): StyledComponent<C, T, O, A>;
<U extends object>(
first:
| TemplateStringsArray
| CSSObject
| InterpolationFunction<ThemedStyledProps<StyledComponentPropsWithRef<C> & O & U, T>>,
...rest: Array<Interpolation<ThemedStyledProps<StyledComponentPropsWithRef<C> & O & U, T>>>
): StyledComponent<C, T, O & U, A>;
}But that is way too complex, I am not sure what to do. What is the type I need to specify for my styledProps?
I'm doing a project from my job and here we use Styled Components to do all the components. I`m trying to implement new approaches to do a clean code without repetition. I have a lot of div's with the code bellow. So I have this question, in this case, when I have the same code from a simple flex div, makes sense set the style directly on a div or it is better create a component with this?
What is the personal rule for you guys to create a new component with styled components?
<div style={{display: 'flex'**,** justifyContent: 'space-between'**,** alignItems: 'center'}}>