https://www.youtube.com/watch?v=LngR9lq-Ozg
const StyledDiv = styled.div`
position: relative;
padding: 10px;
`;
const StyledApp = styled(App)`
position: relative;
padding: 10px;
`;
styled.div
orstyled(App)
is tag function.
Tag functions:
const myMessage = message`
Hello ${name},
Very Good ${time}
`;
function message(strings, ...expression) {
// string will be array of static part ["Hello ", ",\nVery Good ", "\n"];
// expressions will be dynamic interpolations [name, time]
}
So for styled component it will be
const StyledApp = styled(App)`
position: relative;
padding: 10px;
color: ${props => props.color};
`
const func = styled(App) // or styled.div
function (styleStrings, ..interpolation) {
//...
}
- styled(App) or styled.div is an HOC with forward ref
- styled.div is shorthand of styled(div)
function styled(Component) {
return (styleStrings, ...interpolations) => {
return forwardRef((props, ref) => {
//...
return <Component ref={ref} {...props} />;
});
};
}
const domElements = ["div", "a", "button" /* ... */];
domElements.forEach((elm) => {
styled[elm] = styled(elm);
});
1st: styled component id
- styled component generates styled componentId using component displayName and file names when babel is used.
- component id -> displayName - hash of (styled component version + name + counter)
- This is used to uniquely identify a styled component on nested styles, server rendering, also for the dynamic classname generation.
2nd: dynamic classname
- styled component generates a new className hash using (componentId, generatedStyleStr (after applying interpolation))
const StyledApp = styled(App)`
position: relative;
color: ${(props) => props.color};
padding: ${DEFAULT_PADDING};
`;
<StyledApp color="red" ref={myComponentRef}>
Styled component will have static styled and interpolation
Static Style strings: ['position: relative;\ncolor: ', '\npadding: ', '\n']; Interpolation : [(props) => props.color, DEFAULT_PADDING];
function styled(Component) {
return (styleStrings, ...interpolations) => {
return forwardRef((props, ref) => {
//...
const evaluatedInterpolation = interpolations.map((expr) => {
if (typeof expr === "function") return expr(props);
return expr;
});
// combine string and interpolation
const generatedStyleStr = combineStaticAndDynamic(
styleStrings,
evaluatedInterpolation
);
// create className
const className = hash(componentId, generatedStyleStr);
// ...
return (
<Component
ref={ref}
{...props}
css=""
className={`${componentId} ${className} ${props.className}`}
/>
);
});
};
}
- styled component uses stylis lib to pre process styles.
const StyledApp = styled(App)`
position: relative;
color: ${(props) => props.color};
&& .some-element {
color: red;
}
`;
-
& will be replaced with generated className
.${className}
, -
They also mark component if there is no interpolation, to avoid heavy computations.
- Props are passed to interpolations
- Props can be filtered through shouldForwardProp,
- You can also make a prop transient prop by prefixing with
$
- Props merges attributes provided with .attr() util
function styled(Component) {
return (styleStrings, ...interpolations) => {
return forwardRef((props, ref) => {
con;
const theme = useContext(ThemeProvider);
const updatedProps = {
theme,
...props,
};
// ...
});
};
}
- uses context, and enhance props with theme
function styled(Component) {
return (styleStrings, ...interpolations) => {
return forwardRef((props, ref) => {
const theme = useContext(ThemeProvider);
const updatedProps = {
theme,
...props,
};
// ...
});
};
}
const StyledApp = styled(Component).witConfig({shouldForwardProp: (prop) => });
- & will be replaced with generated className
.${className}
, - For nested element context of & will change.
- Due to & replacement reverse selector is supported.
const StyledApp = styled(App)`
position: relative;
color: ${(props) => props.color};
.some-element {
color: red;
}
`;
- For Nesting Styled Component componentId's are used. Note the nested component must be Styled component
const StyledApp = styled(App)`
position: relative;
color: ${(props) => props.color};
${Children} {
color: red;
}
`;
- Show demo
- Support interpolation
function createGlobalStyle(strings, ...interpolations) {
return (props) => {
// generate styles through app
const evaluatedInterpolation = interpolations.map((expr) => {
if (typeof expr === "function") return expr(props);
return expr;
});
// combine string and interpolation
const generatedStyleStr = combineStaticAndDynamic(
styleStrings,
evaluatedInterpolation
);
const styles = stylis(generatedStyleStr);
useEffect(() => {
// append to styles rules to style tag
}, style);
return null;
};
}
- Generates component id during compilation using babel plugin
- Use Context to push generated styles to a collectStyles.