| # styled-jsx |
|
|
| [](https://github.com/vercel/styled-jsx/actions?query=branch%3Amain) |
|
|
| Full, scoped and component-friendly CSS support for JSX (rendered on the server or the client). |
|
|
| Code and docs are for v3 which we highly recommend you to try. Looking for styled-jsx v2? Switch to the [v2 branch](https://github.com/vercel/styled-jsx/tree/v2). |
|
|
| - [Getting started](#getting-started) |
| - [Configuration options](#configuration-options) |
| - [`optimizeForSpeed`](#optimizeforspeed) |
| - [`sourceMaps`](#sourcemaps) |
| - [`styleModule`](#stylemodule) |
| - [`vendorPrefixes`](#vendorprefixes) |
| - [Features](#features) |
| - [How It Works](#how-it-works) |
| - [Why It Works Like This](#why-it-works-like-this) |
| - [Targeting The Root](#targeting-the-root) |
| - [Global styles](#global-styles) |
| - [One-off global selectors](#one-off-global-selectors) |
| - [Dynamic styles](#dynamic-styles) |
| - [Via interpolated dynamic props](#via-interpolated-dynamic-props) |
| - [Via `className` toggling](#via-classname-toggling) |
| - [Via inline `style`](#via-inline-style) |
| - [Constants](#constants) |
| - [Server-Side Rendering](#server-side-rendering) |
| - [External CSS and styles outside of the component](#external-css-and-styles-outside-of-the-component) |
| - [External styles](#external-styles) |
| - [Styles outside of components](#styles-outside-of-components) |
| - [The `resolve` tag](#the-resolve-tag) |
| - [Styles in regular CSS files](#styles-in-regular-css-files) |
| - [CSS Preprocessing via Plugins](#css-preprocessing-via-plugins) |
| - [Plugin options](#plugin-options) |
| - [Example plugins](#example-plugins) |
| - [Rendering in tests](#rendering-in-tests) |
| - [FAQ](#faq) |
| - [Warning: unknown `jsx` prop on <style> tag](#warning-unknown-jsx-prop-on-style-tag) |
| - [Can I return an array of components when using React 16?](#can-i-return-an-array-of-components-when-using-react-16) |
| - [Styling third parties / child components from the parent](#styling-third-parties--child-components-from-the-parent) |
| - [Some styles are missing in production](https://github.com/vercel/styled-jsx/issues/319#issuecomment-349239326) |
| - [Build a component library with styled-jsx](#build-a-component-library-with-styled-jsx) |
| - [Syntax Highlighting](#syntax-highlighting) |
| - [ESLint](#eslint) |
| - [TypeScript](#typescript) |
| - [Credits](#credits) |
|
|
| ## Getting started |
|
|
| Firstly, install the package: |
|
|
| ```bash |
| npm install --save styled-jsx |
| ``` |
|
|
| Next, add `styled-jsx/babel` to `plugins` in your babel configuration: |
|
|
| ```json |
| { |
| "plugins": ["styled-jsx/babel"] |
| } |
| ``` |
|
|
| Now add `<style jsx>` to your code and fill it with CSS: |
|
|
| ```jsx |
| export default () => ( |
| <div> |
| <p>only this paragraph will get the style :)</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> |
| ) |
| ``` |
|
|
| ## Configuration options |
|
|
| The following are optional settings for the babel plugin. |
|
|
| #### `optimizeForSpeed` |
|
|
| Blazing fast and optimized CSS rules injection system based on the CSSOM APIs. |
|
|
| ```json |
| { |
| "plugins": [["styled-jsx/babel", { "optimizeForSpeed": true }]] |
| } |
| ``` |
|
|
| When in production\* this mode is automatically enabled.<br> |
| Beware that when using this option source maps cannot be generated and styles cannot be edited via the devtools. |
|
|
| \* `process.env.NODE_ENV === 'production'` |
|
|
| #### `sourceMaps` |
|
|
| Generates source maps (default: `false`) |
|
|
| #### `styleModule` |
|
|
| Module that the transpiled files should import (default: `styled-jsx/style`) |
|
|
| #### `vendorPrefixes` |
|
|
| Turn on/off automatic vendor prefixing (default: `true`) |
|
|
| ## Features |
|
|
| - Full CSS support, no tradeoffs in power |
| - Runtime size of just **3kb** (gzipped, from 12kb) |
| - Complete isolation: Selectors, animations, keyframes |
| - Built-in CSS vendor prefixing |
| - Very fast, minimal and efficient transpilation (see below) |
| - High-performance runtime-CSS-injection when not server-rendering |
| - Future-proof: Equivalent to server-renderable "Shadow CSS" |
| - Source maps support |
| - Dynamic styles and themes support |
| - CSS Preprocessing via Plugins |
|
|
| ## Using in Next.js |
|
|
| Next.js automatically configures `styled-jsx` with babel or swc, you don't have to configure it manually. |
|
|
| ## How It Works |
|
|
| The example above transpiles to the following: |
|
|
| ```jsx |
| import _JSXStyle from 'styled-jsx/style' |
| |
| export default () => ( |
| <div className="jsx-123"> |
| <p className="jsx-123">only this paragraph will get the style :)</p> |
| <_JSXStyle id="123">{`p.jsx-123 {color: red;}`}</_JSXStyle> |
| </div> |
| ) |
| ``` |
|
|
| ### Why It Works Like This |
|
|
| Unique classnames give us style encapsulation and `_JSXStyle` is heavily optimized for: |
|
|
| - Injecting styles upon render |
| - Only injecting a certain component's style once (even if the component is included multiple times) |
| - Removing unused styles |
| - Keeping track of styles for server-side rendering |
|
|
| ### Targeting The Root |
|
|
| Notice that the outer `<div>` from the example above also gets a `jsx-123` classname. We do this so that |
| you can target the "root" element, in the same manner that |
| [`:host`](https://www.html5rocks.com/en/tutorials/webcomponents/shadowdom-201/#toc-style-host) works with Shadow DOM. |
|
|
| If you want to target _only_ the host, we suggest you use a class: |
|
|
| ```jsx |
| export default () => ( |
| <div className="root"> |
| <style jsx>{` |
| .root { |
| color: green; |
| } |
| `}</style> |
| </div> |
| ) |
| ``` |
|
|
| ### Global styles |
|
|
| To skip scoping entirely, you can make the global-ness of your styles |
| explicit by adding _global_. |
|
|
| ```jsx |
| export default () => ( |
| <div> |
| <style jsx global>{` |
| body { |
| background: red; |
| } |
| `}</style> |
| </div> |
| ) |
| ``` |
|
|
| The advantage of using this over `<style>` is twofold: no need |
| to use `dangerouslySetInnerHTML` to avoid escaping issues with CSS |
| and take advantage of `styled-jsx`'s de-duping system to avoid |
| the global styles being inserted multiple times. |
|
|
| ### One-off global selectors |
|
|
| Sometimes it's useful to skip selectors scoping. In order to get a one-off global selector we support `:global()`, inspired by [css-modules](https://github.com/css-modules/css-modules). |
|
|
| This is very useful in order to, for example, generate a _global class_ that |
| you can pass to 3rd-party components. For example, to style |
| `react-select` which supports passing a custom class via `optionClassName`: |
|
|
| ```jsx |
| import Select from 'react-select' |
| export default () => ( |
| <div> |
| <Select optionClassName="react-select" /> |
| |
| <style jsx>{` |
| /* "div" will be prefixed, but ".react-select" won't */ |
| |
| div :global(.react-select) { |
| color: red; |
| } |
| `}</style> |
| </div> |
| ) |
| ``` |
|
|
| ### Dynamic styles |
|
|
| To make a component's visual representation customizable from the outside world there are three options. |
|
|
| #### Via interpolated dynamic props |
|
|
| Any value that comes from the component's `render` method scope is treated as dynamic. This makes it possible to use `props` and `state` for example. |
|
|
| ```jsx |
| const Button = props => ( |
| <button> |
| {props.children} |
| <style jsx>{` |
| button { |
| padding: ${'large' in props ? '50' : '20'}px; |
| background: ${props.theme.background}; |
| color: #999; |
| display: inline-block; |
| font-size: 1em; |
| } |
| `}</style> |
| </button> |
| ) |
| ``` |
|
|
| New styles' injection is optimized to perform well at runtime. |
|
|
| That said when your CSS is mostly static we recommend to split it up in static and dynamic styles and use two separate `style` tags so that, when changing, only the dynamic parts are recomputed/rendered. |
|
|
| ```jsx |
| const Button = props => ( |
| <button> |
| {props.children} |
| <style jsx>{` |
| button { |
| color: #999; |
| display: inline-block; |
| font-size: 2em; |
| } |
| `}</style> |
| <style jsx>{` |
| button { |
| padding: ${'large' in props ? '50' : '20'}px; |
| background: ${props.theme.background}; |
| } |
| `}</style> |
| </button> |
| ) |
| ``` |
|
|
| #### Via `className` toggling |
|
|
| The second option is to pass properties that toggle class names. |
|
|
| ```jsx |
| const Button = props => ( |
| <button className={'large' in props && 'large'}> |
| {props.children} |
| <style jsx>{` |
| button { |
| padding: 20px; |
| background: #eee; |
| color: #999; |
| } |
| .large { |
| padding: 50px; |
| } |
| `}</style> |
| </button> |
| ) |
| ``` |
|
|
| Then you would use this component as either `<Button>Hi</Button>` or `<Button large>Big</Button>`. |
|
|
| #### Via inline `style` |
|
|
| \***best for animations** |
| |
| Imagine that you wanted to make the padding in the button above completely customizable. You can override the CSS you configure via inline-styles: |
| |
| ```jsx |
| const Button = ({ padding, children }) => ( |
| <button style={{ padding }}> |
| {children} |
| <style jsx>{` |
| button { |
| padding: 20px; |
| background: #eee; |
| color: #999; |
| } |
| `}</style> |
| </button> |
| ) |
| ``` |
| |
| In this example, the padding defaults to the one set in `<style>` (`20`), but the user can pass a custom one via `<Button padding={30}>`. |
| |
| ### Constants |
| |
| It is possible to use constants like so: |
| |
| ```jsx |
| import { colors, spacing } from '../theme' |
| import { invertColor } from '../theme/utils' |
| |
| const Button = ({ children }) => ( |
| <button> |
| {children} |
| <style jsx>{` |
| button { |
| padding: ${spacing.medium}; |
| background: ${colors.primary}; |
| color: ${invertColor(colors.primary)}; |
| } |
| `}</style> |
| </button> |
| ) |
| ``` |
| |
| Please keep in mind that constants defined outside of the component scope are treated as static styles. |
| |
| ## Server-Side Rendering |
| |
| `styled-jsx` v5 introduced `StyledRegistry` component and `useStyleRegistry` hook to let you scope styles rendering in each SSR render to keep concurrent-safe. |
| |
| - `registry.styles()` will return the array of react components for style tags. |
| - `registry.flush()` can clean the existing styles in the registry, it's optional for SSR when you have a standalone registry for each SSR render. |
| |
| > Next.js 12 integrates with `styled-jsx` v5 and manages the registry for you. |
| |
| ```jsx |
| import React from 'react' |
| import ReactDOM from 'react-dom/server' |
| import { StyleRegistry, useStyleRegistry } from 'styled-jsx' |
| import App from './app' |
| |
| function Styles() { |
| const registry = useStyleRegistry() |
| const styles = registry.styles() |
| return <>{styles}</> |
| } |
| |
| export default (req, res) => { |
| const app = ReactDOM.renderToString(<App />) |
| const html = ReactDOM.renderToStaticMarkup( |
| <StyleRegistry> |
| <html> |
| <head> |
| <Styles /> |
| </head> |
| <body> |
| <div id="root" dangerouslySetInnerHTML={{ __html: app }} /> |
| </body> |
| </html> |
| </StyleRegistry> |
| ) |
| res.end('<!doctype html>' + html) |
| } |
| ``` |
| |
| There's also a new API `createStyleRegistry` that is introduced when you have to create a registry manually. In this way you can operate the registry yourself to extract the rendered styles (`registry.styles()`) or flush them out (`registry.flush()`). |
| |
| ```js |
| const registry = createStyleRegistry() |
| const styles = registry.styles() // access styles |
| |
| function Page() { |
| return ( |
| <StyleRegistry registry={registry}> |
| <App /> |
| </StyleRegistry> |
| ) |
| } |
| ``` |
| |
| By default `<StyleRegistry />` will use the `registry` from root top `StyleRegistry`, which means there's only one `registry` in the react tree. |
| |
| It's **paramount** that you use one of these two functions so that |
| the generated styles can be diffed when the client loads and |
| duplicate styles are avoided. |
|
|
| ### Content Security Policy |
|
|
| Strict [CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) is supported. |
|
|
| You should generate a nonce **per request**. |
|
|
| ```js |
| import nanoid from 'nanoid' |
| |
| const nonce = Buffer.from(nanoid()).toString('base64') //ex: N2M0MDhkN2EtMmRkYi00MTExLWFhM2YtNDhkNTc4NGJhMjA3 |
| ``` |
|
|
| You must then pass a nonce to `registry.styles({ nonce })` **and** set a `<meta property="csp-nonce" content={nonce} />` tag. |
|
|
| Your CSP policy must share the same nonce as well (the header nonce needs to match the html nonce and remain unpredictable). |
| `Content-Security-Policy: default-src 'self'; style-src 'self' 'nonce-N2M0MDhkN2EtMmRkYi00MTExLWFhM2YtNDhkNTc4NGJhMjA3';` |
|
|
| ### External CSS and styles outside of the component |
|
|
| In styled-jsx styles can be defined outside of the component's render method or in separate JavaScript modules using the `styled-jsx/css` library. `styled-jsx/css` exports three tags that can be used to tag your styles: |
|
|
| - `css`, the default export, to define scoped styles. |
| - `css.global` to define global styles. |
| - `css.resolve` to define scoped styles that resolve to the scoped `className` and a `styles` element. |
|
|
| #### External styles |
|
|
| In an external file: |
|
|
| ```js |
| /* styles.js */ |
| import css from 'styled-jsx/css' |
| |
| // Scoped styles |
| export const button = css` |
| button { |
| color: hotpink; |
| } |
| ` |
| |
| // Global styles |
| export const body = css.global`body { margin: 0; }` |
| |
| // Resolved styles |
| export const link = css.resolve`a { color: green; }` |
| // link.className -> scoped className to apply to `a` elements e.g. jsx-123 |
| // link.styles -> styles element to render inside of your component |
| |
| // Works also with default exports |
| export default css` |
| div { |
| color: green; |
| } |
| ` |
| ``` |
|
|
| You can then import and use those styles: |
|
|
| ```jsx |
| import styles, { button, body } from './styles' |
| |
| export default () => ( |
| <div> |
| <button>styled-jsx</button> |
| <style jsx>{styles}</style> |
| <style jsx>{button}</style> |
| <style jsx global> |
| {body} |
| </style> |
| </div> |
| ) |
| ``` |
|
|
| N.B. All the tags except for [`resolve`](#the-resolve-tag) don't support dynamic styles. |
|
|
| `resolve` and `global` can also be imported individually: |
|
|
| ```js |
| import { resolve } from 'styled-jsx/css' |
| import { global } from 'styled-jsx/css' |
| ``` |
|
|
| If you use Prettier we recommend you to use the default `css` export syntax since the tool doesn't support named imports. |
|
|
| #### Styles outside of components |
|
|
| The `css` tag from `styled-jsx/css` can be also used to define styles in your components files but outside of the component itself. This might help with keeping `render` methods smaller. |
|
|
| ```jsx |
| import css from 'styled-jsx/css' |
| |
| export default () => ( |
| <div> |
| <button>styled-jsx</button> |
| <style jsx>{button}</style> |
| </div> |
| ) |
| |
| const button = css` |
| button { |
| color: hotpink; |
| } |
| ` |
| ``` |
|
|
| Like in externals styles `css` doesn't work with dynamic styles. If you have dynamic parts you might want to place them inline inside of your component using a regular `<style jsx>` element. |
|
|
| #### The `resolve` tag |
|
|
| The `resolve` tag from `styled-jsx/css` can be used when you need to scope some CSS - for example, if you need to style nested components from the parent, such as the `Link` component in the example below. |
|
|
| It works by returning the generated scoped `className` and related `styles`. |
|
|
| ```jsx |
| import React from 'react' |
| import Link from 'some-library' |
| |
| import css from 'styled-jsx/css' |
| |
| const { className, styles } = css.resolve` |
| a { color: green } |
| ` |
| |
| export default () => ( |
| <div> |
| {/* use the className */} |
| <Link className={className}>About</Link> |
| |
| {/* render the styles for it */} |
| {styles} |
| </div> |
| ) |
| ``` |
|
|
| The `resolve` tag also supports dynamic styles, via template string interpolation: |
|
|
| ```jsx |
| import React from 'react' |
| import css from 'styled-jsx/css' |
| |
| function getLinkStyles(color) { |
| return css.resolve` |
| a { color: ${color} } |
| ` |
| } |
| |
| export default props => { |
| const { className, styles } = getLinkStyles(props.theme.color) |
| |
| return ( |
| <div> |
| <Link className={className}>About</Link> |
| {styles} |
| </div> |
| ) |
| } |
| ``` |
|
|
| #### Using `resolve` as a Babel macro |
|
|
| If you can't (or would rather not) make changes to your `.babelrc`, the `resolve` tag can be used as a Babel macro, thanks to the [`babel-plugin-macros`](https://github.com/kentcdodds/babel-plugin-macros) system. |
|
|
| To set this up, first of all, install `styled-jsx` and `babel-plugin-macros`: |
|
|
| ```bash |
| npm i --save styled-jsx |
| npm i --save-dev babel-plugin-macros |
| ``` |
|
|
| Next, add `babel-plugin-macros` to your Babel configuration: |
|
|
| ```json |
| { |
| "plugins": ["babel-plugin-macros"] |
| } |
| ``` |
|
|
| You can then use `resolve` by importing it from `styled-jsx/macro`. |
|
|
| ```jsx |
| import css from 'styled-jsx/macro' |
| |
| const { className, styles } = css.resolve` |
| a { color: green } |
| ` |
| |
| export default () => ( |
| <div> |
| <Link className={className}>About</Link> |
| {styles} |
| </div> |
| ) |
| ``` |
|
|
| ##### Usage with [`create-react-app`](https://create-react-app.dev) |
|
|
| [Create React App](https://create-react-app.dev) comes with `babel-plugin-macros` already installed, so the only thing that needs to be done is to install `styled-jsx`: |
|
|
| ```bash |
| npm i --save styled-jsx |
| ``` |
|
|
| Then `resolve` can be imported from `styled-jsx/macro` and used the same way as in the example in the [Using `resolve` as a Babel macro](https://github.com/vercel/styled-jsx/blob/main/readme.md#using-resolve-as-a-babel-macro) section above. |
|
|
| #### Styles in regular CSS files |
|
|
| styled-jsx v3 comes with a webpack loader that lets you write styles in regular `css` files and consume them in React. |
|
|
| ```js |
| import styles from '../components/button/styles.css' |
| |
| export default () => ( |
| <div> |
| <button>styled-jsx</button> |
| <style jsx>{styles}</style> |
| </div> |
| ) |
| ``` |
|
|
| To consume the styles in your component you can import them from your CSS file and render them using a `<style jsx>` tag. Remember to add the `global` prop if you want your styles to be global. |
|
|
| To use this feature you need to register the loader in your webpack config file, before `babel-loader` which will then transpile the styles via `styled-jsx/babel` |
|
|
| ```js |
| config: { |
| module: { |
| rules: [ |
| { |
| test: /\.css$/, |
| use: [ |
| { |
| loader: require('styled-jsx/webpack').loader, |
| options: { |
| type: 'scoped' |
| } |
| } |
| ] |
| } |
| ] |
| } |
| } |
| ``` |
|
|
| The plugin accepts a `type` option to configure whether the styles should be `scoped`, `global` or `resolve` (see above). By default its values is set to `scoped`. `type` can also be a `function` which takes the `fileName` and the `fileNameQuery` that is being transpiled and must return a valid type. |
|
|
| ```js |
| type validTypes = 'scoped' | 'global' | 'resolve' |
| type fileName = string |
| type Options = {| |
| type: validTypes | ((fileName, options) => validTypes) |
| |} |
| ``` |
|
|
| ```js |
| import styles from './styles.css?type=global' |
| |
| // webpack |
| config: { |
| module: { |
| rules: [ |
| { |
| test: /\.css$/, |
| use: [ |
| { |
| loader: require('styled-jsx/webpack').loader, |
| options: { |
| type: (fileName, options) => options.query.type || 'scoped' |
| } |
| } |
| ] |
| } |
| ] |
| } |
| } |
| ``` |
|
|
| The type can also be set per individual CSS file via CSS comment: |
|
|
| ```css |
| /* @styled-jsx=scoped */ |
| |
| button { |
| color: red; |
| } |
| ``` |
|
|
| The CSS comment option will override the one in the webpack configuration only for this specific file. |
|
|
| ##### Next.js |
|
|
| Example of `next.config.js` to integrate `styled-jsx/webpack`: |
|
|
| ```js |
| module.exports = { |
| webpack: (config, { defaultLoaders }) => { |
| config.module.rules.push({ |
| test: /\.css$/, |
| use: [ |
| defaultLoaders.babel, |
| { |
| loader: require('styled-jsx/webpack').loader, |
| options: { |
| type: 'scoped' |
| } |
| } |
| ] |
| }) |
| |
| return config |
| } |
| } |
| ``` |
|
|
| ## CSS Preprocessing via Plugins |
|
|
| Styles can be preprocessed via plugins. |
|
|
| Plugins are regular JavaScript modules that export a simple function with the following signature: |
|
|
| ```ts |
| function plugin(css: string, options: Object): string |
| ``` |
|
|
| Basically they accept a CSS string in input, optionally modify it and finally return it. |
|
|
| Plugins make it possible to use popular preprocessors like SASS, Less, Stylus, PostCSS or apply custom transformations to the styles at **compile time**. |
|
|
| To register a plugin add an option `plugins` for `styled-jsx/babel` to your `.babelrc`. `plugins` must be an array of module names or _full_ paths for local plugins. |
|
|
| ```json |
| { |
| "plugins": [ |
| [ |
| "styled-jsx/babel", |
| { |
| "plugins": [ |
| "my-styled-jsx-plugin-package", |
| "/full/path/to/local/plugin" |
| ] |
| } |
| ] |
| ] |
| } |
| ``` |
|
|
| <details> |
| <summary>Instructions to integrate with Next.js</summary> |
| In order to register styled-jsx plugins in a Next.js app you need to create a custom .babelrc file: |
|
|
| ```json |
| { |
| "presets": [ |
| [ |
| "next/babel", |
| { |
| "styled-jsx": { |
| "plugins": ["styled-jsx-plugin-postcss"] |
| } |
| } |
| ] |
| ] |
| } |
| ``` |
|
|
| This is a fairly new feature so make sure that you using a version of Next.js that supports passing options to `styled-jsx`. |
|
|
| </details> |
| <br> |
|
|
| Plugins are applied in definition order left to right before styles are scoped. |
|
|
| In order to resolve local plugins paths you can use NodeJS' [require.resolve](https://nodejs.org/api/globals.html#globals_require_resolve). |
|
|
| N.B. when applying the plugins styled-jsx replaces template literals expressions with placeholders because otherwise CSS parsers would get invalid CSS E.g. |
|
|
| ```css |
| /* `ExprNumber` is a number */ |
| %%styled-jsx-placeholder-ExprNumber%% |
| ``` |
|
|
| **Plugins won't transform expressions** (eg. dynamic styles). |
|
|
| When publishing a plugin you may want to add the keywords: `styled-jsx` and `styled-jsx-plugin`. |
| We also encourage you to use the following naming convention for your plugins: |
|
|
| ``` |
| styled-jsx-plugin-<your-plugin-name> |
| ``` |
|
|
| #### Plugin options |
|
|
| Users can set plugin options by registering a plugin as an array that contains |
| the plugin path and an options object. |
|
|
| ```json |
| { |
| "plugins": [ |
| [ |
| "styled-jsx/babel", |
| { |
| "plugins": [ |
| ["my-styled-jsx-plugin-package", { "exampleOption": true }] |
| ], |
| "sourceMaps": true |
| } |
| ] |
| ] |
| } |
| ``` |
|
|
| Each plugin receives a `options` object as second argument which contains |
| the babel and user options: |
|
|
| ```js |
| ;(css, options) => { |
| /* ... */ |
| } |
| ``` |
|
|
| The `options` object has the following shape: |
|
|
| ```js |
| { |
| // user options go here |
| // eg. exampleOption: true |
| |
| // babel options |
| babel: { |
| sourceMaps: boolean, |
| vendorPrefixes: boolean, |
| isGlobal: boolean, |
| filename: ?string, // defined only when the filename option is passed to Babel, such as when using Babel CLI or Webpack |
| location: { // the original location of the CSS block in the JavaScript file |
| start: { |
| line: number, |
| column: number, |
| }, |
| end: { |
| line: number, |
| column: number, |
| } |
| } |
| } |
| } |
| ``` |
|
|
| #### Example plugins |
|
|
| The following plugins are proof of concepts/sample: |
|
|
| - [styled-jsx-plugin-sass](https://github.com/giuseppeg/styled-jsx-plugin-sass) |
| - [styled-jsx-plugin-postcss](https://github.com/giuseppeg/styled-jsx-plugin-postcss) |
| - [styled-jsx-plugin-stylelint](https://github.com/giuseppeg/styled-jsx-plugin-stylelint) |
| - [styled-jsx-plugin-less](https://github.com/erasmo-marin/styled-jsx-plugin-less) |
| - [styled-jsx-plugin-stylus](https://github.com/omardelarosa/styled-jsx-plugin-stylus) |
|
|
| ## Rendering in tests |
|
|
| If you're using a tool such as Enzyme, you might want to avoid compiling your styles in test renders. In general, styled-jsx artifacts like `jsx-123` classnames and vendor prefixing are not direct concerns of your component, and they generate a lot of snapshot noise. |
|
|
| One option is to exclude the `styled-jsx/babel` plugin from the `test` environment using `env` in your Babel config (see [Config Merging options](https://babeljs.io/docs/en/options#config-merging-options)). |
|
|
| But this can cause noise in your terminal output when rendering: |
|
|
| ``` |
| console.error node_modules/react-dom/cjs/react-dom.development.js:527 |
| Warning: Received `true` for a non-boolean attribute `jsx`. |
| ``` |
|
|
| The `styled-jsx/babel-test` solves this problem. It simply strips `jsx` attributes from all `<style>` tags. Be sure to target each environment with the appropriate plugin: |
|
|
| ```json |
| { |
| "env": { |
| "production": { |
| "plugins": ["styled-jsx/babel"] |
| }, |
| "development": { |
| "plugins": ["styled-jsx/babel"] |
| }, |
| "test": { |
| "plugins": ["styled-jsx/babel-test"] |
| } |
| } |
| } |
| ``` |
|
|
| #### styled-jsx/css in tests |
|
|
| When using `styled-jsx/babel-test`, `styled-jsx/css` throws the following error: |
|
|
| ``` |
| styled-jsx/css: if you are getting this error it means that your `css` tagged template literals were not transpiled. |
| ``` |
|
|
| to solve this issue you need to mock `styled-jsx/css`. You can find a guide at the following link https://kevinjalbert.com/jest-snapshots-reducing-styled-jsx-noise/ |
|
|
| ## FAQ |
|
|
| ### Warning: unknown `jsx` prop on <style> tag |
|
|
| If you get this warning it means that your styles were not compiled by styled-jsx. |
|
|
| Please take a look at your setup and make sure that everything is correct and that the styled-jsx transformation is ran by Babel. |
|
|
| ### Can I return an array of components when using React 16? |
|
|
| No, this feature is not supported. However we support React Fragments, which are available in React `16.2.0` and above. |
|
|
| ```jsx |
| const StyledImage = ({ src, alt = '' }) => ( |
| <React.Fragment> |
| <img src={src} alt={alt} /> |
| <style jsx>{` |
| img { |
| max-width: 100%; |
| } |
| `}</style> |
| </React.Fragment> |
| ) |
| ``` |
|
|
| ### Styling third parties / child components from the parent |
|
|
| When the component accepts a `className` (or ad-hoc) prop as a way to allow customizations then you can use [the `resolve` tag from `styled-jsx/css`](#the-resolve-tag). |
|
|
| When the component doesn't accept any `className` or doesn't expose any API to customize the component, then your only option is to use `:global()` styles: |
|
|
| ```jsx |
| export default () => ( |
| <div> |
| <ExternalComponent /> |
| |
| <style jsx>{` |
| /* "div" will be prefixed, but ".nested-element" won't */ |
| |
| div > :global(.nested-element) { |
| color: red; |
| } |
| `}</style> |
| </div> |
| ) |
| ``` |
|
|
| Please keep in mind that `:global()` styles will affect the entire subtree, so in many cases you may want to be careful and use the children (direct descendant) selector `>`. |
|
|
| ### Build a component library with styled-jsx |
|
|
| There's an [article](https://medium.com/@tomaszmularczyk89/guide-to-building-a-react-components-library-with-rollup-and-styled-jsx-694ec66bd2) explaining how to bundle React components with Rollup and styled-jsx as an external dependency. |
|
|
| ## Syntax Highlighting |
|
|
| When working with template literals a common drawback is missing syntax highlighting. The following editors currently have support for highlighting CSS inside `<style jsx>` elements. |
|
|
| _If you have a solution for an editor not on the list_ **please [open a PR](https://github.com/vercel/styled-jsx/pull/new/main)** _and let us now._ |
|
|
| ### Atom |
|
|
| The [`language-babel`](https://github.com/gandm/language-babel) package for the [Atom editor](https://atom.io/) has an option to [extend the grammar for JavaScript tagged template literals](https://github.com/gandm/language-babel#javascript-tagged-template-literal-grammar-extensions). |
|
|
| After [installing the package](https://github.com/gandm/language-babel#installation) add the code below to the appropriate settings entry. In a few moments you should be blessed with proper CSS syntax highlighting. ([source](https://github.com/gandm/language-babel/issues/324)) |
|
|
| ``` |
| "(?<=<style jsx>{)|(?<=<style jsx global>{)|(?<=css)":source.css.styled |
| ``` |
|
|
|  |
|
|
| ### Webstorm/Idea |
|
|
| The IDE let you inject any language in place with _Inject language or reference_ in an _Intention Actions_ (default _alt+enter_). |
| Simply perform the action in the string template and select CSS. |
| You get full CSS highlighting and autocompletion and it will last until you close the IDE. |
|
|
| Additionally you can use language injection comments to enable all the IDE language features indefinitely using the language comment style: |
|
|
| ```jsx |
| import { colors, spacing } from '../theme' |
| import { invertColor } from '../theme/utils' |
| |
| const Button = ({ children }) => ( |
| <button> |
| {children} |
| |
| {/*language=CSS*/} |
| <style jsx>{` |
| button { |
| padding: ${spacing.medium}; |
| background: ${colors.primary}; |
| color: ${invertColor(colors.primary)}; |
| } |
| `}</style> |
| </button> |
| ) |
| ``` |
|
|
| ### Emmet |
|
|
| If you're using Emmet you can add the following snippet to `~/emmet/snippets-styledjsx.json` This will allow you to expand `style-jsx` to a styled-jsx block. |
|
|
| ```json |
| { |
| "html": { |
| "snippets": { |
| "style-jsx": "<style jsx>{`\n\t$1\n`}</style>" |
| } |
| } |
| } |
| ``` |
|
|
| ### Syntax Highlighting [Visual Studio Code Extension](https://marketplace.visualstudio.com/items?itemName=Divlo.vscode-styled-jsx-syntax) |
|
|
| Launch VS Code Quick Open (⌘+P), paste the following command, and press enter. |
|
|
| ``` |
| ext install Divlo.vscode-styled-jsx-syntax |
| ``` |
|
|
| If you use Stylus instead of plain CSS, install [vscode-styled-jsx-stylus](https://marketplace.visualstudio.com/items?itemName=samuelroy.vscode-styled-jsx-stylus) or paste the command below. |
|
|
| ``` |
| ext install vscode-styled-jsx-stylus |
| ``` |
|
|
| ### Autocomplete [Visual Studio Code Extension](https://marketplace.visualstudio.com/items?itemName=Divlo.vscode-styled-jsx-languageserver) |
|
|
| Launch VS Code Quick Open (⌘+P), paste the following command, and press enter. |
|
|
| ``` |
| ext install Divlo.vscode-styled-jsx-languageserver |
| ``` |
|
|
| ### Vim |
|
|
| Install [vim-styled-jsx](https://github.com/alampros/vim-styled-jsx) with your plugin manager of choice. |
|
|
| ## ESLint |
|
|
| If you're using `eslint-plugin-import`, the `css` import will generate errors, being that it's a "magic" import (not listed in package.json). To avoid these, simply add the following line to your eslint configuration: |
|
|
| ``` |
| "settings": {"import/core-modules": ["styled-jsx/css"] } |
| ``` |
|
|
| ## TypeScript |
|
|
| If you're using TypeScript, then in order to allow `<style jsx>` tags to be properly understood by it, create a file named "styled-jsx.d.ts" anywhere within your project containing the following, or add this line to the top of any single existing .ts file within your project: |
|
|
| ```ts |
| /// <reference types="styled-jsx" /> |
| ``` |
|
|
| > If you're using babel to transform styled-jsx code with TypeScript, you need to specify `"jsx": "preserve"` in your tsconfig.json to keep the original JSX and let babel parse and transform with styled-jsx babel plugin. |
|
|
| ## Credits |
|
|
| - **Pedram Emrouznejad** ([rijs](https://github.com/rijs/fullstack)) suggested attribute selectors over my initial class prefixing idea. |
| - **Sunil Pai** ([glamor](https://github.com/threepointone/glamor)) inspired the use of `murmurhash2` (minimal and fast hashing) and an efficient style injection logic. |
| - **Sultan Tarimo** built [stylis.js](https://github.com/thysultan), a super fast and tiny CSS parser and compiler. |
| - **Max Stoiber** ([styled-components](https://github.com/styled-components)) proved the value of retaining the familiarity of CSS syntax and pointed me to the very efficient [stylis](https://github.com/thysultan/stylis.js) compiler (which we forked to very efficiently append attribute selectors to the user's css) |
| - **Yehuda Katz** ([ember](https://github.com/emberjs)) convinced me on Twitter to transpile CSS as an alternative to CSS-in-JS. |
| - **Evan You** ([vuejs](https://github.com/vuejs)) discussed his Vue.js CSS transformation with me. |
| - **Henry Zhu** ([babel](https://github.com/babel)) helpfully pointed me to some important areas of the babel plugin API. |
|
|
| ## Authors |
|
|
| - Guillermo Rauch ([@rauchg](https://twitter.com/rauchg)) - [▲Vercel](https://vercel.com) |
| - Naoyuki Kanezawa ([@nkzawa](https://twitter.com/nkzawa)) - [▲Vercel](https://vercel.com) |
| - Giuseppe Gurgone ([@giuseppegurgone](https://twitter.com/giuseppegurgone)) |
|
|