1 | # styled-jsx
|
2 |
|
3 | [![Build Status](https://travis-ci.org/zeit/styled-jsx.svg?branch=master)](https://travis-ci.org/zeit/styled-jsx)
|
4 |
|
5 | Need help?<br>
|
6 | [![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/styled-jsx)
|
7 |
|
8 | Full, scoped and component-friendly CSS support for JSX (rendered on the server or the client).
|
9 |
|
10 | 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/zeit/styled-jsx/tree/v2).
|
11 |
|
12 | - [Getting started](#getting-started)
|
13 | - [Configuration options](#configuration-options)
|
14 | * [`optimizeForSpeed`](#optimizeforspeed)
|
15 | * [`sourceMaps`](#sourcemaps)
|
16 | * [`vendorPrefixes`](#vendorprefixes)
|
17 | - [Features](#features)
|
18 | - [How It Works](#how-it-works)
|
19 | * [Why It Works Like This](#why-it-works-like-this)
|
20 | - [Targeting The Root](#targeting-the-root)
|
21 | - [Global styles](#global-styles)
|
22 | * [One-off global selectors](#one-off-global-selectors)
|
23 | - [Dynamic styles](#dynamic-styles)
|
24 | * [Via interpolated dynamic props](#via-interpolated-dynamic-props)
|
25 | * [Via `className` toggling](#via-classname-toggling)
|
26 | * [Via inline `style`](#via-inline-style)
|
27 | - [Constants](#constants)
|
28 | - [Server-Side Rendering](#server-side-rendering)
|
29 | * [`styled-jsx/server`](#styled-jsxserver)
|
30 | - [External CSS and styles outside of the component](#external-css-and-styles-outside-of-the-component)
|
31 | * [External styles](#external-styles)
|
32 | * [Styles outside of components](#styles-outside-of-components)
|
33 | * [The `resolve` tag](#the-resolve-tag)
|
34 | * [Styles in regular CSS files](#styles-in-regular-css-files)
|
35 | - [CSS Preprocessing via Plugins](#css-preprocessing-via-plugins)
|
36 | * [Plugin options](#plugin-options)
|
37 | * [Example plugins](#example-plugins)
|
38 | - [Rendering in tests](#rendering-in-tests)
|
39 | - [FAQ](#faq)
|
40 | * [Warning: unknown `jsx` prop on <style> tag](#warning-unknown-jsx-prop-on-style-tag)
|
41 | * [Can I return an array of components when using React 16?](#can-i-return-an-array-of-components-when-using-react-16)
|
42 | * [Styling third parties / child components from the parent](#styling-third-parties--child-components-from-the-parent)
|
43 | * [Some styles are missing in production](https://github.com/zeit/styled-jsx/issues/319#issuecomment-349239326)
|
44 | * [Build a component library with styled-jsx](#build-a-component-library-with-styled-jsx)
|
45 | - [Syntax Highlighting](#syntax-highlighting)
|
46 |
|
47 | ## Getting started
|
48 |
|
49 | Firstly, install the package:
|
50 |
|
51 | ```bash
|
52 | npm install --save styled-jsx
|
53 | ```
|
54 |
|
55 | Next, add `styled-jsx/babel` to `plugins` in your babel configuration:
|
56 |
|
57 | ```json
|
58 | {
|
59 | "plugins": [
|
60 | "styled-jsx/babel"
|
61 | ]
|
62 | }
|
63 | ```
|
64 |
|
65 | Now add `<style jsx>` to your code and fill it with CSS:
|
66 |
|
67 | ```jsx
|
68 | export default () => (
|
69 | <div>
|
70 | <p>only this paragraph will get the style :)</p>
|
71 |
|
72 | { /* you can include <Component />s here that include
|
73 | other <p>s that don't get unexpected styles! */ }
|
74 |
|
75 | <style jsx>{`
|
76 | p {
|
77 | color: red;
|
78 | }
|
79 | `}</style>
|
80 | </div>
|
81 | )
|
82 | ```
|
83 |
|
84 | ## Configuration options
|
85 |
|
86 | The following are optional settings for the babel plugin.
|
87 |
|
88 | #### `optimizeForSpeed`
|
89 |
|
90 | Blazing fast and optimized CSS rules injection system based on the CSSOM APIs.
|
91 |
|
92 | ```json
|
93 | {
|
94 | "plugins": [
|
95 | ["styled-jsx/babel", { "optimizeForSpeed": true }]
|
96 | ]
|
97 | }
|
98 | ```
|
99 | When in production\* this mode is automatically enabled.<br>
|
100 | Beware that when using this option source maps cannot be generated and styles cannot be edited via the devtools.
|
101 |
|
102 | \* `process.env.NODE_ENV === 'production'`
|
103 |
|
104 |
|
105 | #### `sourceMaps`
|
106 |
|
107 | Generates source maps (default: `false`)
|
108 |
|
109 | #### `vendorPrefixes`
|
110 |
|
111 | Turn on/off automatic vendor prefixing (default: `true`)
|
112 |
|
113 | ## Features
|
114 |
|
115 | - Full CSS support, no tradeoffs in power
|
116 | - Runtime size of just **3kb** (gzipped, from 12kb)
|
117 | - Complete isolation: Selectors, animations, keyframes
|
118 | - Built-in CSS vendor prefixing
|
119 | - Very fast, minimal and efficient transpilation (see below)
|
120 | - High-performance runtime-CSS-injection when not server-rendering
|
121 | - Future-proof: Equivalent to server-renderable "Shadow CSS"
|
122 | - Source maps support
|
123 | - Dynamic styles and themes support
|
124 | - CSS Preprocessing via Plugins
|
125 |
|
126 | ## How It Works
|
127 |
|
128 | The example above transpiles to the following:
|
129 |
|
130 | ```jsx
|
131 | import _JSXStyle from 'styled-jsx/style'
|
132 |
|
133 | export default () => (
|
134 | <div className="jsx-123">
|
135 | <p className="jsx-123">only this paragraph will get the style :)</p>
|
136 | <_JSXStyle id="123">{`p.jsx-123 {color: red;}`}</_JSXStyle>
|
137 | </div>
|
138 | )
|
139 | ```
|
140 |
|
141 | ### Why It Works Like This
|
142 |
|
143 | Unique classnames give us style encapsulation and `_JSXStyle` is heavily optimized for:
|
144 |
|
145 | - Injecting styles upon render
|
146 | - Only injecting a certain component's style once (even if the component is included multiple times)
|
147 | - Removing unused styles
|
148 | - Keeping track of styles for server-side rendering
|
149 |
|
150 | ### Targeting The Root
|
151 |
|
152 | Notice that the outer `<div>` from the example above also gets a `jsx-123` classname. We do this so that
|
153 | you can target the "root" element, in the same manner that
|
154 | [`:host`](https://www.html5rocks.com/en/tutorials/webcomponents/shadowdom-201/#toc-style-host) works with Shadow DOM.
|
155 |
|
156 | If you want to target _only_ the host, we suggest you use a class:
|
157 |
|
158 | ```jsx
|
159 | export default () => (
|
160 | <div className="root">
|
161 | <style jsx>{`
|
162 | .root {
|
163 | color: green;
|
164 | }
|
165 | `}</style>
|
166 | </div>
|
167 | )
|
168 | ```
|
169 |
|
170 | ### Global styles
|
171 |
|
172 | To skip scoping entirely, you can make the global-ness of your styles
|
173 | explicit by adding _global_.
|
174 |
|
175 | ```jsx
|
176 | export default () => (
|
177 | <div>
|
178 | <style jsx global>{`
|
179 | body {
|
180 | background: red
|
181 | }
|
182 | `}</style>
|
183 | </div>
|
184 | )
|
185 | ```
|
186 |
|
187 | The advantage of using this over `<style>` is twofold: no need
|
188 | to use `dangerouslySetInnerHTML` to avoid escaping issues with CSS
|
189 | and take advantage of `styled-jsx`'s de-duping system to avoid
|
190 | the global styles being inserted multiple times.
|
191 |
|
192 | ### One-off global selectors
|
193 |
|
194 | 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).
|
195 |
|
196 | This is very useful in order to, for example, generate a *global class* that
|
197 | you can pass to 3rd-party components. For example, to style
|
198 | `react-select` which supports passing a custom class via `optionClassName`:
|
199 |
|
200 | ```jsx
|
201 | import Select from 'react-select'
|
202 | export default () => (
|
203 | <div>
|
204 | <Select optionClassName="react-select" />
|
205 |
|
206 | <style jsx>{`
|
207 | /* "div" will be prefixed, but ".react-select" won't */
|
208 |
|
209 | div :global(.react-select) {
|
210 | color: red
|
211 | }
|
212 | `}</style>
|
213 | </div>
|
214 | )
|
215 | ```
|
216 |
|
217 | ### Dynamic styles
|
218 |
|
219 | To make a component's visual representation customizable from the outside world there are three options.
|
220 |
|
221 | #### Via interpolated dynamic props
|
222 |
|
223 | 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.
|
224 |
|
225 | ```jsx
|
226 | const Button = (props) => (
|
227 | <button>
|
228 | { props.children }
|
229 | <style jsx>{`
|
230 | button {
|
231 | padding: ${ 'large' in props ? '50' : '20' }px;
|
232 | background: ${props.theme.background};
|
233 | color: #999;
|
234 | display: inline-block;
|
235 | font-size: 1em;
|
236 | }
|
237 | `}</style>
|
238 | </button>
|
239 | )
|
240 | ```
|
241 |
|
242 | New styles' injection is optimized to perform well at runtime.
|
243 |
|
244 | 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.
|
245 |
|
246 | ```jsx
|
247 | const Button = (props) => (
|
248 | <button>
|
249 | { props.children }
|
250 | <style jsx>{`
|
251 | button {
|
252 | color: #999;
|
253 | display: inline-block;
|
254 | font-size: 2em;
|
255 | }
|
256 | `}</style>
|
257 | <style jsx>{`
|
258 | button {
|
259 | padding: ${ 'large' in props ? '50' : '20' }px;
|
260 | background: ${props.theme.background};
|
261 | }
|
262 | `}</style>
|
263 | </button>
|
264 | )
|
265 | ```
|
266 |
|
267 | #### Via `className` toggling
|
268 |
|
269 | The second option is to pass properties that toggle class names.
|
270 |
|
271 | ```jsx
|
272 | const Button = (props) => (
|
273 | <button className={ 'large' in props && 'large' }>
|
274 | { props.children }
|
275 | <style jsx>{`
|
276 | button {
|
277 | padding: 20px;
|
278 | background: #eee;
|
279 | color: #999
|
280 | }
|
281 | .large {
|
282 | padding: 50px
|
283 | }
|
284 | `}</style>
|
285 | </button>
|
286 | )
|
287 | ```
|
288 |
|
289 | Then you would use this component as either `<Button>Hi</Button>` or `<Button large>Big</Button>`.
|
290 |
|
291 | #### Via inline `style`
|
292 |
|
293 | \***best for animations**
|
294 |
|
295 | Imagine that you wanted to make the padding in the button above completely customizable. You can override the CSS you configure via inline-styles:
|
296 |
|
297 | ```jsx
|
298 | const Button = ({ padding, children }) => (
|
299 | <button style={{ padding }}>
|
300 | { children }
|
301 | <style jsx>{`
|
302 | button {
|
303 | padding: 20px;
|
304 | background: #eee;
|
305 | color: #999
|
306 | }
|
307 | `}</style>
|
308 | </button>
|
309 | )
|
310 | ```
|
311 |
|
312 | 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}>`.
|
313 |
|
314 | ### Constants
|
315 |
|
316 | It is possible to use constants like so:
|
317 |
|
318 | ```jsx
|
319 | import { colors, spacing } from '../theme'
|
320 | import { invertColor } from '../theme/utils'
|
321 |
|
322 | const Button = ({ children }) => (
|
323 | <button>
|
324 | { children }
|
325 | <style jsx>{`
|
326 | button {
|
327 | padding: ${ spacing.medium };
|
328 | background: ${ colors.primary };
|
329 | color: ${ invertColor(colors.primary) };
|
330 | }
|
331 | `}</style>
|
332 | </button>
|
333 | )
|
334 | ```
|
335 |
|
336 | Please keep in mind that constants defined outside of the component scope are treated as static styles.
|
337 |
|
338 | ## Server-Side Rendering
|
339 |
|
340 | ### `styled-jsx/server`
|
341 |
|
342 | The main export flushes your styles to an array of `React.Element`:
|
343 |
|
344 | ```jsx
|
345 | import React from 'react'
|
346 | import ReactDOM from 'react-dom/server'
|
347 | import flush from 'styled-jsx/server'
|
348 | import App from './app'
|
349 |
|
350 | export default (req, res) => {
|
351 | const app = ReactDOM.renderToString(<App />)
|
352 | const styles = flush()
|
353 | const html = ReactDOM.renderToStaticMarkup(<html>
|
354 | <head>{ styles }</head>
|
355 | <body>
|
356 | <div id="root" dangerouslySetInnerHTML={{__html: app}} />
|
357 | </body>
|
358 | </html>)
|
359 | res.end('<!doctype html>' + html)
|
360 | }
|
361 | ```
|
362 |
|
363 | We also expose `flushToHTML` to return generated HTML:
|
364 |
|
365 | ```jsx
|
366 | import React from 'react'
|
367 | import ReactDOM from 'react-dom/server'
|
368 | import { flushToHTML } from 'styled-jsx/server'
|
369 | import App from './app'
|
370 |
|
371 | export default (req, res) => {
|
372 | const app = ReactDOM.renderToString(<App />)
|
373 | const styles = flushToHTML()
|
374 | const html = `<!doctype html>
|
375 | <html>
|
376 | <head>${styles}</head>
|
377 | <body>
|
378 | <div id="root">${app}</div>
|
379 | </body>
|
380 | </html>`
|
381 | res.end(html)
|
382 | }
|
383 | ```
|
384 |
|
385 | It's **paramount** that you use one of these two functions so that
|
386 | the generated styles can be diffed when the client loads and
|
387 | duplicate styles are avoided.
|
388 |
|
389 | ### Content Security Policy
|
390 |
|
391 | Strict [CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) is supported.
|
392 |
|
393 | You should generate a nonce **per request**.
|
394 | ```js
|
395 | import nanoid from 'nanoid'
|
396 |
|
397 | const nonce = Buffer.from(nanoid()).toString('base64') //ex: N2M0MDhkN2EtMmRkYi00MTExLWFhM2YtNDhkNTc4NGJhMjA3
|
398 | ```
|
399 |
|
400 | You must then pass a nonce to either `flushToReact({ nonce })` or `flushToHTML({ nonce })` **and** set a `<meta property="csp-nonce" content={nonce} />` tag.
|
401 |
|
402 | Your CSP policy must share the same nonce as well (the header nonce needs to match the html nonce and remain unpredictable).
|
403 | `Content-Security-Policy: default-src 'self'; style-src 'self' 'nonce-N2M0MDhkN2EtMmRkYi00MTExLWFhM2YtNDhkNTc4NGJhMjA3';`
|
404 |
|
405 | ### External CSS and styles outside of the component
|
406 |
|
407 | 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:
|
408 |
|
409 | * `css`, the default export, to define scoped styles.
|
410 | * `css.global` to define global styles.
|
411 | * `css.resolve` to define scoped styles that resolve to the scoped `className` and a `styles` element.
|
412 |
|
413 | #### External styles
|
414 |
|
415 | In an external file:
|
416 |
|
417 | ```js
|
418 | /* styles.js */
|
419 | import css from 'styled-jsx/css'
|
420 |
|
421 | // Scoped styles
|
422 | export const button = css`button { color: hotpink; }`
|
423 |
|
424 | // Global styles
|
425 | export const body = css.global`body { margin: 0; }`
|
426 |
|
427 | // Resolved styles
|
428 | export const link = css.resolve`a { color: green; }`
|
429 | // link.className -> scoped className to apply to `a` elements e.g. jsx-123
|
430 | // link.styles -> styles element to render inside of your component
|
431 |
|
432 | // Works also with default exports
|
433 | export default css`div { color: green; }`
|
434 | ```
|
435 |
|
436 | You can then import and use those styles:
|
437 |
|
438 | ```jsx
|
439 | import styles, { button, body } from './styles'
|
440 |
|
441 | export default () => (
|
442 | <div>
|
443 | <button>styled-jsx</button>
|
444 | <style jsx>{styles}</style>
|
445 | <style jsx>{button}</style>
|
446 | <style jsx global>{body}</style>
|
447 | </div>
|
448 | )
|
449 | ```
|
450 |
|
451 | N.B. All the tags except for [`resolve`](#the-resolve-tag) don't support dynamic styles.
|
452 |
|
453 | `resolve` and `global` can also be imported individually:
|
454 |
|
455 | ```js
|
456 | import { resolve } from 'styled-jsx/css'
|
457 | import { global } from 'styled-jsx/css'
|
458 | ```
|
459 |
|
460 | If you use Prettier we recommend you to use the default `css` export syntax since the tool doesn't support named imports.
|
461 |
|
462 | #### Styles outside of components
|
463 |
|
464 | 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.
|
465 |
|
466 | ```jsx
|
467 | import css from 'styled-jsx/css'
|
468 |
|
469 | export default () => (
|
470 | <div>
|
471 | <button>styled-jsx</button>
|
472 | <style jsx>{button}</style>
|
473 | </div>
|
474 | )
|
475 |
|
476 | const button = css`button { color: hotpink; }`
|
477 | ```
|
478 |
|
479 | 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.
|
480 |
|
481 | #### The `resolve` tag
|
482 |
|
483 | The `resolve` tag from `styled-jsx/css` can be used when you need to scope some CSS and want back the generated scoped `className` and `styles`. This is usually the case when you want to style nested components from the parent.
|
484 |
|
485 | ```jsx
|
486 | import React from 'react'
|
487 | import Link from 'some-library'
|
488 |
|
489 | import css from 'styled-jsx/css'
|
490 |
|
491 | const { className, styles } = css.resolve`
|
492 | a { color: green }
|
493 | `
|
494 |
|
495 | export default () => (
|
496 | <div>
|
497 | {/* use the className */}
|
498 | <Link className={className}>About</Link>
|
499 | {/* render the styles for it */}
|
500 | {styles}
|
501 | <style jsx>{`div { border: 5px solid green }`}</style>
|
502 | </div>
|
503 | )
|
504 | ```
|
505 |
|
506 | The `resolve` tag also supports dynamic styles:
|
507 |
|
508 | ```jsx
|
509 | import React from 'react'
|
510 | import css from 'styled-jsx/css'
|
511 |
|
512 | function getLinkStyles(color) {
|
513 | return css.resolve`
|
514 | a { color: ${color} }
|
515 | `
|
516 | }
|
517 |
|
518 | export default (props) => {
|
519 | const { className, styles } = getLinkStyles(props.theme.color)
|
520 |
|
521 | return (
|
522 | <div>
|
523 | <Link className={className}>About</Link>
|
524 | {styles}
|
525 | </div>
|
526 | )
|
527 | }
|
528 | ```
|
529 |
|
530 | #### Using `resolve` as a babel macro
|
531 |
|
532 | The `resolve` tag can be used as a Babel macro thanks to the [`babel-plugin-macros`](https://github.com/kentcdodds/babel-plugin-macros) system.
|
533 |
|
534 | ```bash
|
535 | npm i --save styled-jsx
|
536 | npm i --save-dev babel-plugin-macros
|
537 | ```
|
538 |
|
539 | Next add `babel-plugin-macros` to your babel configuration:
|
540 |
|
541 | ```json
|
542 | {
|
543 | "plugins": [
|
544 | "babel-plugin-macros"
|
545 | ]
|
546 | }
|
547 | ```
|
548 |
|
549 | You can then start to use `resolve` by importing it from `styled-jsx/macro`.
|
550 |
|
551 | ```jsx
|
552 | import css, { resolve } from 'styled-jsx/macro'
|
553 |
|
554 | const stylesInfo = css.resolve`a { color: green; }`
|
555 | const stylesInfo2 = resolve`a { color: green; }`
|
556 | ```
|
557 |
|
558 | **Create React App** comes with `babel-plugin-macros` pre-installed so you just need to install `styled-jsx` and you can start to use `resolve` right away.
|
559 |
|
560 |
|
561 | #### Styles in regular CSS files
|
562 |
|
563 | styled-jsx v3 comes with a webpack loader that lets you write styles in regular `css` files and consume them in React.
|
564 |
|
565 | ```js
|
566 | import styles from '../components/button/styles.css'
|
567 |
|
568 | export default () => (
|
569 | <div>
|
570 | <button>styled-jsx</button>
|
571 | <style jsx>{styles}</style>
|
572 | </div>
|
573 | )
|
574 | ```
|
575 |
|
576 | 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.
|
577 |
|
578 | 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`
|
579 |
|
580 | ```js
|
581 | config: {
|
582 | module: {
|
583 | rules: [
|
584 | test: /\.css$/,
|
585 | use: [{
|
586 | loader: require('styled-jsx/webpack').loader,
|
587 | options: {
|
588 | type: 'scoped'
|
589 | }
|
590 | }]
|
591 | ]
|
592 | }
|
593 | }
|
594 | ```
|
595 |
|
596 | 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.
|
597 |
|
598 | ```js
|
599 | type validTypes = 'scoped' | 'global' | 'resolve'
|
600 | type fileName = string
|
601 | type Options = {|
|
602 | type: validTypes | (fileName, options) => validTypes
|
603 | |}
|
604 | ```
|
605 | ```js
|
606 | import styles from './styles.css?type=global'
|
607 |
|
608 | // webpack
|
609 | config: {
|
610 | module: {
|
611 | rules: [
|
612 | test: /\.css$/,
|
613 | use: [{
|
614 | loader: require('styled-jsx/webpack').loader,
|
615 | options: {
|
616 | type: (fileName, options) => options.query.type || 'scoped'
|
617 | }
|
618 | }]
|
619 | ]
|
620 | }
|
621 | }
|
622 | ```
|
623 |
|
624 | The type can also be set per individual CSS file via CSS comment:
|
625 |
|
626 | ```css
|
627 | /* @styled-jsx=scoped */
|
628 |
|
629 | button { color: red }
|
630 | ```
|
631 |
|
632 | The CSS comment option will override the one in the webpack configuration only for this specific file.
|
633 |
|
634 | ##### Next.js
|
635 |
|
636 | Example of `next.config.js` to integrate `styled-jsx/webpack`:
|
637 |
|
638 | ```js
|
639 | module.exports = {
|
640 | webpack: (config, { defaultLoaders }) => {
|
641 | config.module.rules.push({
|
642 | test: /\.css$/,
|
643 | use: [
|
644 | defaultLoaders.babel,
|
645 | {
|
646 | loader: require('styled-jsx/webpack').loader,
|
647 | options: {
|
648 | type: 'scoped'
|
649 | }
|
650 | }
|
651 | ]
|
652 | })
|
653 |
|
654 | return config
|
655 | }
|
656 | }
|
657 | ```
|
658 |
|
659 | ## CSS Preprocessing via Plugins
|
660 |
|
661 | Styles can be preprocessed via plugins.
|
662 |
|
663 | Plugins are regular JavaScript modules that export a simple function with the following signature:
|
664 |
|
665 | ```js
|
666 | (css: string, options: Object) => string
|
667 | ```
|
668 |
|
669 | Basically they accept a CSS string in input, optionally modify it and finally return it.
|
670 |
|
671 | Plugins make it possible to use popular preprocessors like SASS, Less, Stylus, PostCSS or apply custom transformations to the styles at **compile time**.
|
672 |
|
673 | 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.
|
674 |
|
675 | ```json
|
676 | {
|
677 | "plugins": [
|
678 | [
|
679 | "styled-jsx/babel",
|
680 | { "plugins": ["my-styled-jsx-plugin-package", "/full/path/to/local/plugin"] }
|
681 | ]
|
682 | ]
|
683 | }
|
684 | ```
|
685 |
|
686 | <details>
|
687 | <summary>Instructions to integrate with Next.js</summary>
|
688 | In order to register styled-jsx plugins in a Next.js app you need to create a custom .babelrc file:
|
689 |
|
690 | ```json
|
691 | {
|
692 | "presets": [
|
693 | [
|
694 | "next/babel",
|
695 | {
|
696 | "styled-jsx": {
|
697 | "plugins": [
|
698 | "styled-jsx-plugin-postcss"
|
699 | ]
|
700 | }
|
701 | }
|
702 | ]
|
703 | ]
|
704 | }
|
705 | ```
|
706 |
|
707 | This is a fairly new feature so make sure that you using a version of Next.js that supports passing options to `styled-jsx`.
|
708 | </details>
|
709 | <br>
|
710 |
|
711 | Plugins are applied in definition order left to right before styles are scoped.
|
712 |
|
713 | In order to resolve local plugins paths you can use NodeJS' [require.resolve](https://nodejs.org/api/globals.html#globals_require_resolve).
|
714 |
|
715 | N.B. when applying the plugins styled-jsx replaces template literals expressions with placeholders because otherwise CSS parsers would get invalid CSS E.g.
|
716 |
|
717 | ```css
|
718 | /* `ExprNumber` is a number */
|
719 | %%styled-jsx-placeholder-ExprNumber%%
|
720 | ```
|
721 |
|
722 | **Plugins won't transform expressions** (eg. dynamic styles).
|
723 |
|
724 | When publishing a plugin you may want to add the keywords: `styled-jsx` and `styled-jsx-plugin`.
|
725 | We also encourage you to use the following naming convention for your plugins:
|
726 |
|
727 | ```
|
728 | styled-jsx-plugin-<your-plugin-name>
|
729 | ```
|
730 |
|
731 | #### Plugin options
|
732 |
|
733 | Users can set plugin options by registering a plugin as an array that contains
|
734 | the plugin path and an options object.
|
735 |
|
736 | ```json
|
737 | {
|
738 | "plugins": [
|
739 | [
|
740 | "styled-jsx/babel",
|
741 | {
|
742 | "plugins": [
|
743 | ["my-styled-jsx-plugin-package", { "exampleOption": true }]
|
744 | ],
|
745 | "sourceMaps": true
|
746 | }
|
747 | ]
|
748 | ]
|
749 | }
|
750 | ```
|
751 |
|
752 | Each plugin receives a `options` object as second argument which contains
|
753 | the babel and user options:
|
754 |
|
755 | ```js
|
756 | (css, options) => { /* ... */ }
|
757 | ```
|
758 |
|
759 | The `options` object has the following shape:
|
760 |
|
761 | ```js
|
762 | {
|
763 | // user options go here
|
764 | // eg. exampleOption: true
|
765 |
|
766 | // babel options
|
767 | babel: {
|
768 | sourceMaps: boolean,
|
769 | vendorPrefixes: boolean,
|
770 | isGlobal: boolean,
|
771 | filename: ?string, // defined only when the filename option is passed to Babel, such as when using Babel CLI or Webpack
|
772 | location: { // the original location of the CSS block in the JavaScript file
|
773 | start: {
|
774 | line: number,
|
775 | column: number,
|
776 | },
|
777 | end: {
|
778 | line: number,
|
779 | column: number,
|
780 | }
|
781 | }
|
782 | }
|
783 | }
|
784 | ```
|
785 |
|
786 | #### Example plugins
|
787 |
|
788 | The following plugins are proof of concepts/sample:
|
789 |
|
790 | * [styled-jsx-plugin-sass](https://github.com/giuseppeg/styled-jsx-plugin-sass)
|
791 | * [styled-jsx-plugin-postcss](https://github.com/giuseppeg/styled-jsx-plugin-postcss)
|
792 | * [styled-jsx-plugin-stylelint](https://github.com/giuseppeg/styled-jsx-plugin-stylelint)
|
793 | * [styled-jsx-plugin-less](https://github.com/erasmo-marin/styled-jsx-plugin-less)
|
794 | * [styled-jsx-plugin-stylus](https://github.com/omardelarosa/styled-jsx-plugin-stylus)
|
795 |
|
796 |
|
797 | ## Rendering in tests
|
798 |
|
799 | 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.
|
800 |
|
801 | 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)).
|
802 |
|
803 | But this can cause noise in your terminal output when rendering:
|
804 |
|
805 | ```
|
806 | console.error node_modules/react-dom/cjs/react-dom.development.js:527
|
807 | Warning: Received `true` for a non-boolean attribute `jsx`.
|
808 | ```
|
809 |
|
810 | 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:
|
811 |
|
812 | ```json
|
813 | {
|
814 | "env": {
|
815 | "production": {
|
816 | "plugins": ["styled-jsx/babel"]
|
817 | },
|
818 | "development": {
|
819 | "plugins": ["styled-jsx/babel"]
|
820 | },
|
821 | "test": {
|
822 | "plugins": ["styled-jsx/babel-test"]
|
823 | }
|
824 | }
|
825 | }
|
826 | ```
|
827 |
|
828 | #### styled-jsx/css in tests
|
829 |
|
830 | When using `styled-jsx/babel-test`, `styled-jsx/css` throws the following error:
|
831 |
|
832 | ```
|
833 | styled-jsx/css: if you are getting this error it means that your `css` tagged template literals were not transpiled.
|
834 | ```
|
835 |
|
836 | 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/
|
837 |
|
838 | ## FAQ
|
839 |
|
840 | ### Warning: unknown `jsx` prop on <style> tag
|
841 |
|
842 | If you get this warning it means that your styles were not compiled by styled-jsx.
|
843 |
|
844 | Please take a look at your setup and make sure that everything is correct and that the styled-jsx transformation is ran by Babel.
|
845 |
|
846 | ### Can I return an array of components when using React 16?
|
847 |
|
848 | No, this feature is not supported. However we support React Fragments, which are available in React `16.2.0` and above.
|
849 |
|
850 | ```jsx
|
851 | const StyledImage = ({ src, alt = '' }) => (
|
852 | <React.Fragment>
|
853 | <img src={src} alt={alt} />
|
854 | <style jsx>{`img { max-width: 100% }`}</style>
|
855 | </React.Fragment>
|
856 | )
|
857 | ```
|
858 |
|
859 | ### Styling third parties / child components from the parent
|
860 |
|
861 | 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).
|
862 |
|
863 | 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:
|
864 |
|
865 | ```jsx
|
866 | export default () => (
|
867 | <div>
|
868 | <ExternalComponent />
|
869 |
|
870 | <style jsx>{`
|
871 | /* "div" will be prefixed, but ".nested-element" won't */
|
872 |
|
873 | div > :global(.nested-element) {
|
874 | color: red
|
875 | }
|
876 | `}</style>
|
877 | </div>
|
878 | )
|
879 | ```
|
880 |
|
881 | 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 `>`.
|
882 |
|
883 | ### Build a component library with styled-jsx
|
884 |
|
885 | 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.
|
886 |
|
887 | ## Syntax Highlighting
|
888 |
|
889 | 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.
|
890 |
|
891 | _If you have a solution for an editor not on the list_ __please [open a PR](https://github.com/zeit/styled-jsx/pull/new/master)__ _and let us now._
|
892 |
|
893 | ### Atom
|
894 |
|
895 | 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).
|
896 |
|
897 | 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))
|
898 |
|
899 | ```
|
900 | "(?<=<style jsx>{)|(?<=<style jsx global>{)|(?<=css)":source.css.styled
|
901 | ```
|
902 |
|
903 | ![babel-language settings entry](https://cloud.githubusercontent.com/assets/2313237/22627258/6c97cb68-ebb7-11e6-82e1-60205f8b31e7.png)
|
904 |
|
905 | ### Webstorm/Idea
|
906 |
|
907 | The IDE let you inject any language in place with _Inject language or reference_ in an _Intention Actions_ (default _alt+enter_).
|
908 | Simply perform the action in the string template and select CSS.
|
909 | You get full CSS highlighting and autocompletion and it will last until you close the IDE.
|
910 |
|
911 | Additionally you can use language injection comments to enable all the IDE language features indefinitely using the language comment style:
|
912 |
|
913 | ```jsx
|
914 | import { colors, spacing } from '../theme'
|
915 | import { invertColor } from '../theme/utils'
|
916 |
|
917 | const Button = ({ children }) => (
|
918 | <button>
|
919 | { children }
|
920 |
|
921 | { /*language=CSS*/ }
|
922 | <style jsx>{`
|
923 | button {
|
924 | padding: ${ spacing.medium };
|
925 | background: ${ colors.primary };
|
926 | color: ${ invertColor(colors.primary) };
|
927 | }
|
928 | `}</style>
|
929 | </button>
|
930 | )
|
931 | ```
|
932 |
|
933 | ### Emmet
|
934 |
|
935 | 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.
|
936 |
|
937 | ```json
|
938 | {
|
939 | "html": {
|
940 | "snippets": {
|
941 | "style-jsx": "<style jsx>{`\n\t$1\n`}</style>"
|
942 | }
|
943 | }
|
944 | }
|
945 | ```
|
946 |
|
947 | ### Syntax Highlighting [Visual Studio Code Extension](https://marketplace.visualstudio.com/items?itemName=blanu.vscode-styled-jsx)
|
948 | Launch VS Code Quick Open (⌘+P), paste the following command, and press enter.
|
949 | ```
|
950 | ext install vscode-styled-jsx
|
951 | ```
|
952 |
|
953 | 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.
|
954 | ```
|
955 | ext install vscode-styled-jsx-stylus
|
956 | ```
|
957 |
|
958 | ### Autocomplete [Visual Studio Code Extension](https://marketplace.visualstudio.com/items?itemName=AndrewRazumovsky.vscode-styled-jsx-languageserver)
|
959 | Launch VS Code Quick Open (⌘+P), paste the following command, and press enter.
|
960 | ```
|
961 | ext install vscode-styled-jsx-languageserver
|
962 | ```
|
963 |
|
964 | ### Vim
|
965 |
|
966 | Install [vim-styled-jsx](https://github.com/alampros/vim-styled-jsx) with your plugin manager of choice.
|
967 |
|
968 | ## ESLint
|
969 | 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:
|
970 |
|
971 | ```
|
972 | "settings": {"import/core-modules": ["styled-jsx/css"] }
|
973 | ```
|
974 |
|
975 | ## Credits
|
976 |
|
977 | - **Pedram Emrouznejad** ([rijs](https://github.com/rijs/fullstack)) suggested attribute selectors over my initial class prefixing idea.
|
978 | - **Sunil Pai** ([glamor](https://github.com/threepointone/glamor)) inspired the use of `murmurhash2` (minimal and fast hashing) and an efficient style injection logic.
|
979 | - **Sultan Tarimo** built [stylis.js](https://github.com/thysultan), a super fast and tiny CSS parser and compiler.
|
980 | - **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)
|
981 | - **Yehuda Katz** ([ember](https://github.com/emberjs)) convinced me on Twitter to transpile CSS as an alternative to CSS-in-JS.
|
982 | - **Evan You** ([vuejs](https://github.com/vuejs)) discussed his Vue.js CSS transformation with me.
|
983 | - **Henry Zhu** ([babel](https://github.com/babel)) helpfully pointed me to some important areas of the babel plugin API.
|
984 |
|
985 | ## Authors
|
986 |
|
987 | - Guillermo Rauch ([@rauchg](https://twitter.com/rauchg)) - [▲ZEIT](https://zeit.co)
|
988 | - Naoyuki Kanezawa ([@nkzawa](https://twitter.com/nkzawa)) - [▲ZEIT](https://zeit.co)
|
989 | - Giuseppe Gurgone ([@giuseppegurgone](https://twitter.com/giuseppegurgone))
|