What is styled-jsx?
The styled-jsx npm package is a CSS-in-JS library that allows you to write encapsulated and scoped CSS to style your components in a React application. It is specifically designed to work with React and Next.js and provides a way to include styles directly within JavaScript or TypeScript files.
What are styled-jsx's main functionalities?
Scoped Styles
This feature allows you to write CSS that is scoped to a component. The styles will not leak to other parts of the application.
<style jsx>{`p { color: red; }`}</style>
Global Styles
With styled-jsx, you can also define global styles that apply to the entire application, not just scoped to a single component.
<style jsx global>{`body { background: black; }`}</style>
Dynamic Styles
styled-jsx supports dynamic styles, allowing you to use JavaScript variables and expressions to determine the styles at runtime.
`<style jsx>{
`p { color: ${color}; }`
}</style>`
Preprocessing
You can use preprocessors with styled-jsx to include external stylesheets or use features like nesting or variables.
<style jsx>{`
@import 'styles/shared.css';
p { color: red; }
`}</style>
Other packages similar to styled-jsx
styled-components
styled-components is another CSS-in-JS library that allows you to use template literals to write actual CSS code in your JavaScript files. It also handles scoping and supports dynamic styling. It differs from styled-jsx in its API and the way styles are applied to components.
emotion
Emotion is a performant and flexible CSS-in-JS library. It allows you to style applications quickly with string or object styles. It has a similar API to styled-components and includes features like composition, theming, and server-side rendering.
linaria
Linaria is a zero-runtime CSS-in-JS library that extracts CSS to separate files during the build process, rather than including styles in the JavaScript bundle. This can result in better performance compared to styled-jsx, which includes styles in the JS bundle.
styled-jsx
Full, scoped and component-friendly CSS support for JSX (SSR+browser)
How it works
Just include <style jsx>
.
export default () => (
<div>
<p>only this paragraph will get the style :O</p>
{ /* you can include <Component />s here that include
other <p>s that don't get unexpected styles! */ }
<style jsx>{`
p {
color: red;
}
`}</style>
</div>
)
Features
- Full CSS support, no tradeoffs in power
- Runtime size: 300b
- Complete isolation: selectors, animations, keyframes
- Built in CSS prefixing
- Very fast, minimal and efficient transpilation (see below)
- High performant runtime CSS injection when not server-rendering
- Future-proof: equivalent to server-renderable "Shadow CSS"
- Works like the deprecated
<style scoped>
, but the styles
get injected only once per component
How it works
The example above compiles to
import _jsxStyleInject from 'styled-jsx/inject'
export default () => (
<div>
<p data-jsx='cn2o3j'>only this paragraph will get the style :O</p>
{ _jsxStyleInject('cn2o3j', `p[data-jsx=cn2o3j] {color: red;}`) }
</div>
)
- Data attributes give us style encapsulation.
_jsxStyleInject
is heavily optimized for:
- injecting styles upon render
- only injecting a certain componen'ts style once, even if the component is included multiple times
- keeping track of styles for server-side rendering
How to use
Add styled-jsx
to dependencies
inside package.json
Babel
Add styled-jsx/babel
to plugins
in your babel configuration
Server-side rendering
In the server rendering pipeline, you can obtain the entire
CSS text of all the combined components by invoking flush
import flush from 'styled-jsx/flush'
const styles = flush()
for (let id in styles) {
const css = styles[id]
console.log(id, css)
}
This API is also available on the client. Instead of returning
the CSS text, it returns a reference to the created <style>
tag.
This is useful for performing diffs of elements between top-level
render()
calls, and ditching style elements that are not longer
used.
Credits
- Pedram Emrouznejad (
rijs
)
- suggesting attribute selectors over my initial class prefixing idea
- Sunil Pail (
glamor
)
- inspired usage of
murmurhash2
(minimal and fast hashing) - efficient style injection logic
- Sultan Tarimo (
stylis.js
)
- super fast and tiny CSS parser and compiler
- Max Stoiber (
styled-components
)
- proved the value of retaining the familiarity of CSS syntax
- pointed me to the very efficient
stylis
compiler which we forked to very efficiently append attribute selectors
to the user's css
- Yehuda Katz (
ember
)
- convinced me on Twitter to transpile CSS as an alternative to CSS-in-JS
- Evan You (
vuejs
)
- discussing his Vue.js CSS transformation
- Henry Zhu (
babel
)
- his helpful pointers on the babel plugin API
Author
Guillermo Rauch (@rauchg - ▲ZEIT