Skip to content

Commit

Permalink
Merge pull request #1718 from flo-sch/docs/jsx-runtime/update-configu…
Browse files Browse the repository at this point in the history
…ration-patterns

Docs: update JSX pragma guide with automatic runtime section
  • Loading branch information
hasparus committed Jun 15, 2021
2 parents 8358f3e + bcc3e7b commit 51f7fd1
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 27 deletions.
41 changes: 28 additions & 13 deletions packages/docs/src/pages/guides/how-it-works.mdx
Expand Up @@ -4,13 +4,16 @@ title: How it Works

# How it Works

Theme UI combines several libraries together to form a mini-framework for styling applications.
Theme UI combines several libraries together to form a mini-framework for
styling applications.

Theme UI is built with:

- [Emotion][]: used to generate isolated CSS with theming context
- [MDX][]: used to provide custom Emotion styled components to MDX documents, without polluting the global CSS scope
- [Typography.js][]: optionally used for creating rich typographic styles with a simple, high-level API
- [MDX][]: used to provide custom Emotion styled components to MDX documents,
without polluting the global CSS scope
- [Typography.js][]: optionally used for creating rich typographic styles with a
simple, high-level API

[emotion]: https://emotion.sh
[mdx]: https://mdxjs.com
Expand All @@ -19,13 +22,16 @@ Theme UI is built with:
## ThemeProvider

The Theme UI `ThemeProvider` component is a wrapper around MDX's `MDXProvider`,
which adds custom React components to context,
and Emotion's `ThemeProvider`, which adds the `theme` object to context for use with Emotion.
which adds custom React components to context, and Emotion's `ThemeProvider`,
which adds the `theme` object to context for use with Emotion.

The Theme UI `ThemeProvider` includes a default `components` object with styled components that pick up values from the `theme.styles` object.
For example, `theme.styles.h1` will be used in its `components.h1` component and rendered in MDX documents.
The Theme UI `ThemeProvider` includes a default `components` object with styled
components that pick up values from the `theme.styles` object. For example,
`theme.styles.h1` will be used in its `components.h1` component and rendered in
MDX documents.

For illustrative purposes, the `ThemeProvider` renders something like the following:
For illustrative purposes, the `ThemeProvider` renders something like the
following:

```jsx
// for demonstration only – this does not reflect the actual source code
Expand All @@ -50,18 +56,20 @@ export default ({ components, theme, children }) => (

## Custom Components

When using the `components` prop to add custom MDX components,
each component is wrapped with the `sx` prop to allow the component to pick up values from the `theme.styles` object.
When using the `components` prop to add custom MDX components, each component is
wrapped with the `sx` prop to allow the component to pick up values from the
`theme.styles` object.

## JSX Pragma

The Theme UI JSX function wraps the Emotion JSX function, converting the `sx` prop to a call to `@theme-ui/css`.
The two examples below yield the same results:
The Theme UI JSX function wraps the Emotion JSX function, converting the `sx`
prop to a call to `@theme-ui/css`. The two examples below yield the same
results:

```jsx
// with Emotion's JSX function
// this is typically handled with the Emotion Babel preset
/** @jsxImportSource @emotion/reaact */
/** @jsxImportSource @emotion/react */
import { css } from 'theme-ui'

export default (props) => (
Expand Down Expand Up @@ -91,3 +99,10 @@ export default (props) => (
/>
)
```

<Note>

Confused about this `@jsxImportSource` comment? Read more about
[JSX Pragma](/guides/jsx-pragma).

</Note>
141 changes: 127 additions & 14 deletions packages/docs/src/pages/guides/jsx-pragma.mdx
Expand Up @@ -4,13 +4,16 @@ title: JSX Pragma

# JSX Pragma

Theme UI uses custom JSX functions and JSX import source comments to allow you to style elements with values from your theme using the [`sx` prop][].
Theme UI uses custom JSX functions and JSX import source comments to allow you
to style elements with values from your theme using the [`sx` prop][].

## What is JSX

JSX is an XML-like syntax extension to JavaScript.
It's a syntax sugar usually used for React's `jsx` function.
You don't need to write JSX to use React, but it's meant to make code more readable, especially for tree structures with attributes.
[JSX](https://facebook.github.io/jsx/) is an XML-like syntax extension to
JavaScript. It's a syntax sugar usually used for
[React's `jsx`](https://reactjs.org/docs/introducing-jsx.html) function. You
don't need to write JSX to use React, but it's meant to make code more readable,
especially for tree structures with attributes.

Given the following JSX:

Expand All @@ -34,19 +37,26 @@ jsx('div', {
})
```

Most apps use Babel to compile JSX syntax for use with React or other similar libraries.
JSX can be compiled to _any_ function call. By default the Babel plugin will convert JSX into calls to the `jsx` function imported from `react/jsx-runtime`, but libraries like Preact, MDX, Emotion, and Vuejs use custom functions to create elements with JSX.
Most apps use Babel to compile JSX syntax for use with React or other similar
libraries. JSX can be compiled to _any_ function call. By default the Babel
plugin will convert JSX into calls to the `jsx` function imported from
`react/jsx-runtime`, but libraries like Preact, MDX, Emotion, and Vuejs use
custom functions to create elements with JSX.

Technically Babel also calls `jsxs` from `react/jsx-runtime` and `jsxDEV` from `react/jsx-dev-runtime` in some cases, but the concept still holds.
Technically Babel also calls `jsxs` from `react/jsx-runtime` and `jsxDEV` from
`react/jsx-dev-runtime` in some cases, but the concept still holds.

To change the underlying create element functions, you can either add an option to the Babel plugin or you can set a _pragma comment_ at the beginning of a module.
Changing the function import source in the Babel plugin will transform all JSX in an application into the same set of functions.
Using a pragma comment limits the change to only the modules that it's added to.
This lets you default to the React `jsx` function in most places and use custom functions only where you need it,
giving the author more control over where it's used.
To change the underlying create element functions, you can either add an option
to the Babel plugin or you can set a _pragma comment_ at the beginning of a
module. Changing the function import source in Babel config will transform all
JSX in an application into the same set of functions. Using a pragma comment
limits the change to only the modules that it's added to. This lets you default
to the React `jsx` function in most places and use custom functions only where
you need it, giving the author more control over where it's used.

Theme UI uses custom create element functions to add the `sx` and `css` props in React.
The preferred way of using these functions is by adding the custom pragma comment to the top of your file.
Theme UI uses custom create element functions to add the `sx` and `css` props in
React. The preferred way of using these functions is by adding the custom pragma
comment to the top of your file.

```js
/** @jsxImportSource theme-ui */
Expand All @@ -55,3 +65,106 @@ The preferred way of using these functions is by adding the custom pragma commen
See the [`sx` prop][] docs to learn more.

[`sx` prop]: /sx-prop

## Automatic JSX runtime

React v17 introduced a
[new JSX transform](https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html),
also called "automatic runtime" (backported to React v16.14.0) If you use any of
those versions together with a configurable transpiler (such as Babel or
TypeScript), you can configure JSX to use the automatic runtime (globally, for
your entire app), and no longer need to use the custom pragma comments in your
files to use `sx`.

Here are a few examples showing how to do that depending how you build your
application:

### Using @babel/preset-react

```js
// babel.config.js
module.exports = {
presets: [
[
'@babel/preset-react',
{
importSource: 'theme-ui', // or '@theme-ui/core'
runtime: 'automatic',
throwIfNamespace: false,
},
],
],
// ...
}
```

NOTE: this requires
[babel >= 7.9.0](https://babeljs.io/docs/en/babel-preset-react#react-automatic-runtime)

### Using @babel/plugin-transform-react-jsx

This plugin is included in the preset above, but can also used as a standalone
babel plugin.

```js
// babel.config.js
module.exports = {
presets: [
[
'@babel/plugin-transform-react-jsx',
{
importSource: 'theme-ui', // or '@theme-ui/core'
runtime: 'automatic',
throwIfNamespace: false,
},
],
],
// ...
}
```

NOTE: this requires
[babel >= 7.9.0](https://babeljs.io/docs/en/babel-plugin-transform-react-jsx#react-automatic-runtime)

### Using TypeScript

If you use TypeScript to transpile your source code with `tsc` (or only
typecheck), or for instance to run tests with `ts-jest`

```json
// tsconfig.json
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "theme-ui"
}
// ...
}
```

NOTE: this requires
[TypeScript >= 4.1](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-1.html#react-17-jsx-factories)

### Using next.js

```js
// babel.config.js
module.exports = {
presets: [
[
'next/babel',
{
'preset-react': {
importSource: 'theme-ui', // or '@theme-ui/core'
runtime: 'automatic',
throwIfNamespace: false,
},
},
],
],
// ...
}
```

You can read more about
[customizing Babel config in Next.js docs](https://nextjs.org/docs/advanced-features/customizing-babel-config).

1 comment on commit 51f7fd1

@vercel
Copy link

@vercel vercel bot commented on 51f7fd1 Jun 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.