React

Parcel works great for building single or multi-page React applications. It includes a first-class development experience with Fast Refresh, and supports JSX, TypeScript, Flow, and many styling methodologies out of the box.

Getting started

#

First, install react and react-dom into your project:

yarn add react react-dom

Most Parcel apps start with an HTML file. Parcel follows the dependencies (such as a <script> tag) from there to build your app.

src/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>My Parcel App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="index.js"></script>
</body>
</html>
src/index.js:
import { createRoot } from "react-dom/client";
import { App } from "./App";

const container = document.getElementById("app");
const root = createRoot(container)
root.render(<App />);
src/App.js:
export function App() {
return <h1>Hello world!</h1>;
}

As you can see, we’ve referenced index.js from a <script> element in our HTML file. This imported react-dom and used it to render our App component into the <div id="app"> element in our page.

See Building a web app with Parcel for more details on getting started with a new project.

JSX

#

Parcel supports JSX automatically when it detects you are using React. If you’re using React 17 or later, it also automatically enables the modern JSX transform, which means you don't even need to import React for JSX to work, as you can see in App.js in the above example.

To learn more about JSX, see Introducing JSX and JSX In Depth in the React docs, and the JSX section from Parcel's JavaScript docs for details on how you can configure some details of how it's handled.

Fast Refresh

#

Parcel has first-class support for React Fast Refresh, which gives you quick feedback as you edit your code without needing to reload the page. In most cases, it can preserve component state as code is edited, even if you make an error. See the Hot reloading docs for details on how this works.

Tips

#

For more tips, see the official React Fast Refresh docs.

TypeScript

#

TypeScript is supported out of the box. You can reference a .ts or .tsx file from your HTML page, and Parcel will compile it as you'd expect.

To add TypeScript definitions for React, install the following packages into your project:

yarn add @types/react @types/react-dom --dev

See the TypeScript docs for more details on using TypeScript with Parcel.

Flow

#

Flow is supported automatically when it is installed. To add it to an existing project, first install flow-bin as a dependency:

yarn add flow-bin --dev

Then, use the // @flow directive at the top of the files you'd like to type check. This also signals to Parcel which files can have Flow types that should be stripped when compiling for the browser.

See the Flow docs for more details on using Flow with Parcel.

Styling

#

Parcel supports many different ways of styling applications written with React.

CSS

#

You can import a CSS file into a JavaScript or TypeScript file to load it along with a component.

Button.js:
import './Button.css';

export function Button({ children }) {
return (
<button className="button">
{children}
</button>
);
}
Button.css:
.button {
background: hotpink;
}

You can also load CSS using a standard <link rel="stylesheet"> element in your HTML file, but referencing CSS from your components helps make it clear which components depend on which CSS. This can also help with code splitting because only the CSS necessary for the components that you render will be loaded.

Parcel also supports CSS languages like SASS, Less, and Stylus. See CSS for more details on how CSS is processed by Parcel.

CSS modules

#

By default, CSS imported from JavaScript is global. If two CSS files define the same class names, they will potentially clash and overwrite each other. To solve this, Parcel supports CSS modules.

CSS modules treat the classes defined in each file as unique. Each class name is renamed to include a unique hash, and a map is exported to JavaScript to allow referencing these renamed class names.

To use CSS modules, create a file with the .module.css extension, and import it from a JavaScript file with a namespace import. Then, you can use the exports of the CSS module when rendering elements in JSX.

Button.js:
import * as classes from './Button.module.css';

export function Button({ children }) {
return (
<button className={classes.button}>
{children}
</button>
);
}
Button.module.css:
.button {
background: hotpink;
}

See CSS modules to learn more about how Parcel handles CSS modules.

CSS-in-JS

#

CSS-in-JS libraries like Styled Components, Emotion, and many others work well with Parcel. Some may require build configuration, such as a Babel plugin. To enable it, create a Babel configuration in your project and Parcel will pick it up automatically.

For example, to use Emotion, install the Babel plugin and create a .babelrc in your project:

yarn add @emotion/babel-plugin --dev
yarn add @emotion/react
.babelrc:
{
"plugins": ["@emotion/babel-plugin"]
}

You’ll also need to set the jsxImportSource option in a tsconfig.json or jsconfig.json so that Emotion's JSX pragma is used instead of the default one. This enables the css prop to work.

jsconfig.json:
{
"compilerOptions": {
"jsxImportSource": "@emotion/react"
}
}

Now, you can render elements with CSS-in-JS:

Button.js:
import { css } from "@emotion/react";

export function Button({ children }) {
return (
<button
css={css`
background: hotpink;
&:hover {
background: purple;
}
`
}

>

{children}
</button>
);
}

Tailwind CSS

#

Tailwind CSS is a popular utility-first CSS framework. It uses PostCSS to build a CSS file containing only the classes you use in your code.

To use it, first, install the necessary dependencies:

yarn add tailwindcss postcss autoprefixer --dev

Next, create the config files needed for PostCSS and Tailwind. This example will use Tailwind’s JIT mode to speed up builds by only compiling the classes you use. Make sure you modify the glob passed to the content option so it matches all of the source files where you'll use Tailwind classes.

.postcssrc:
{
"plugins": {
"tailwindcss": {}
}
}
tailwind.config.js:
module.exports = {
content: ["./src/*.{html,js}"],
theme: {
extend: {},
},
variants: {},
plugins: [],
};

Finally, you can reference Tailwind classes from any files that match the content glob listed in tailwind.config.js.

Button.js:
export function Button({ children }) {
return (
<button className="p-2 rounded bg-blue-500 hover:bg-blue-600 transition">
{children}
</button>
);
}

Images

#

You can reference external images from JSX using the URL constructor. Parcel also supports using query parameters to resize and convert images to a different format. It also handles image optimization, and includes a content hash in output filenames for long term browser caching.

Logo.js:
const logo = new URL('logo.svg', import.meta.url);

export function Logo() {
return <img src={logo} alt="logo" />;
}

See URL dependencies in the JavaScript docs for more details about this syntax, and the Image docs for more information about how Parcel handles images.

SVG

#

External SVG files can be referenced as described above. You can also import SVGs as React components which can be rendered directly in JSX.

First, install the @parcel/transformer-svg-react plugin and add it to your .parcelrc:

yarn add @parcel/transformer-svg-react --dev
.parcelrc:
{
"extends": "@parcel/config-default",
"transformers": {
"*.svg": ["...", "@parcel/transformer-svg-react"]
}
}

Now, you can import SVGs from your component files and render them just like any other component.

AddButton.js:
import AddIcon from "./AddIcon.svg";

export function AddButton() {
return (
<button aria-label="Add">
<AddIcon />
</button>
);
}

The above example showed how to convert every SVG file to JSX, but you may want to be more selective in some cases. See Importing as a React component in the SVG docs for more details.

See the SVG docs for more about how Parcel transforms and optimizes SVG files.

Code splitting

#

Code splitting helps reduce initial page load size by lazily loading sections of your app. This can be accomplished by using the dynamic import() syntax, along with React.lazy.

This example lazily loads a Profile component when a user clicks a button. When it sees the dynamic import(), Parcel moves the Profile component into a separate bundle from the Home component and loads it on demand. React.lazy handles turning this into a component, and Suspense handles rendering a fallback while it is loading.

Home.js:
import React, {Suspense} from 'react';

const Profile = React.lazy(() => import('./Profile'));

export function Home() {
let [showProfile, setShowProfile] = React.useState(false);

return (
<main>
<h1>Home</h1>
<button onClick={() => setShowProfile(true)}>
Show Profile
</button>
{showProfile &&
<Suspense fallback={<div>Loading...</div>}>
<Profile />
</Suspense>
}
</main>
);
}
Profile.js:
export default function Profile() {
return <h2>Profile</h2>;
}

See the Code Splitting docs for more details about code splitting in Parcel, and Code Splitting in the React docs for more about Suspense and React.lazy.