Intro
Anyone who has used Styled Components, that popular, powerful CSS-in-JS library, for any length of time has come across odd bugs that involve the renderer completely ignoring a style or several, sometimes for an entire component, initiating a frantic search for the root of the problem. I'll spare you the trouble: the culprit is often nested interpolation.
const nestedInterp = `
color: ${props => (props.black ? 'black' : 'white')};
${/*
Without the `css` helper, the above function is cast as a string.
*/''}
`;
const Div = styled.div`
${props => (props.active ? 'color: red;' : nestedInterp)};
`;
This is a caveat that beginners often stumble upon instead of read about, as syntactic sugar is meant to be inconspicuous. Template literals cast all interpolated values to strings, thus interpolated functions normally yield empty strings. Interpolated functions work as they do with Styled Components because the styled
object's members are tagged templates that provide that functionality. However, as with template literals, the returned values of interpolated functions are cast as strings. This means that nested interpolated functions are cast as well. For more information, read about how string interpolation and tagged templates work "under-the-hood."
The Solution
To solve this, Styled Components added a helper function named simply css
that also accepts a tagged template as its parameter. It forwards props to any interpolations and handles any interpolated functions, just like styled
. In addition, many devs working with Styled Components will configure their linters to detect and resolve neglected nested interpolations. Unfortunately, linters are not fool-proof and edge cases often pop up in complex, destructured, deeply-nested UI component libraries.
Thus, the developer community has recommended using the css
helper function for every nested template literal, whether or not the literal includes an interpolated function. In addition to the issues of unhandled nested interpolations and difficult-to-lint edge cases, this best practice resolves a number of other concerns:
- Memory leaks in server-side rendered apps.
- Providing a target to syntax highlighters and linters.
- Minification and transpilation.
- Future-proofing for interoperability and precompilation.
Top comments (0)