diff --git a/packages/docs/src/pages/guides/how-it-works.mdx b/packages/docs/src/pages/guides/how-it-works.mdx index 618251930..7ab15a5cf 100644 --- a/packages/docs/src/pages/guides/how-it-works.mdx +++ b/packages/docs/src/pages/guides/how-it-works.mdx @@ -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 @@ -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 @@ -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) => ( @@ -91,3 +99,10 @@ export default (props) => ( /> ) ``` + + + +Confused about this `@jsxImportSource` comment? Read more about +[JSX Pragma](/guides/jsx-pragma). + + diff --git a/packages/docs/src/pages/guides/jsx-pragma.mdx b/packages/docs/src/pages/guides/jsx-pragma.mdx index f106726b3..b86167360 100644 --- a/packages/docs/src/pages/guides/jsx-pragma.mdx +++ b/packages/docs/src/pages/guides/jsx-pragma.mdx @@ -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: @@ -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 */ @@ -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).