diff --git a/docs/framework-integration/react.md b/docs/framework-integration/react.md
index 750ab6f15..5dd18875d 100644
--- a/docs/framework-integration/react.md
+++ b/docs/framework-integration/react.md
@@ -1,7 +1,7 @@
---
title: React Integration with Stencil
sidebar_label: React
-description: React Integration with Stencil
+description: Learn how to wrap your components so that people can use them natively in React
slug: /react
contributors:
- jthoms1
@@ -12,229 +12,507 @@ contributors:
- danawoodman
- a-giuliano
- rwaskiewicz
+ - tanner-reits
---
# React Integration
**Supports: React v16.7+ • TypeScript 3.7+ • Stencil v2.9.0+**
-Stencil provides a wrapper for your custom elements to be used as first-class React components. The goal of a wrapper is to easily integrate your Stencil components into a specific framework. Wrappers provide a function that you can use within Stencil’s Output Targets to automatically create components for the targeted framework that wrap the web components you create in a Stencil project.
+Stencil can generate React component wrappers for your web components. This allows your Stencil components to be used within
+a React application. The benefits of using Stencil's component wrappers over the standard web components include:
-One benefit of the wrapper pattern includes improved maintainability since you can write code once, and reuse it across different frameworks. Today, there are some challenges associated with using HTML Custom Elements in a React app. Custom events are not handled properly, as well as properties/attributes that are not a string or number. By using Stencil's component wrappers, you can solve these issues and receive first-class React components.
+- Custom events will be handled correctly and correctly propagate through the React render tree
+- Properties and attributes that are not a string or number will be correctly bound to the component
## Setup
### Project Structure
-To organize the generated component libraries for different frameworks, we recommend using a monorepo structure. This monorepo will contain your Stencil component library as well as the component libraries for whatever frameworks you choose. The overall structure of a monorepo with Stencil and React component libraries might look something like this
+We recommend using a [monorepo](https://www.toptal.com/front-end/guide-to-monorepos) structure for your component library with component
+wrappers. Your project workspace should contain your Stencil component library and the library for the generated React component wrappers.
+
+An example project set-up may look similar to:
```
top-most-directory/
-├── stencil-library/
-│ ├── stencil.config.js
-│ └── src/components/
-└── react-library/
- └── src/
- ├── components/
- └── index.ts
+└── packages/
+ ├── stencil-library/
+ │ ├── stencil.config.js
+ │ └── src/components/
+ └── react-library/
+ └── src/
+ ├── components/
+ └── index.ts
```
-To do this, start by creating a monorepo
+This guide uses Lerna for the monorepo, but you can use other solutions such as Nx, TurboRepo, etc.
-```bash
-mkdir {the name of your monorepo}
+To use Lerna with this walk through, globally install Lerna:
+
+```bash npm2yarn
+npm install --global lerna
```
-And then move your Stencil component library into your monorepo
+#### Creating a Monorepo
-```bash
-mv {the path to your Stencil component library} {the path to your monorepo}
-```
+:::note
+If you already have a monorepo, skip this section.
+:::
-### Create a React Component Library
+```bash npm2yarn
+# From your top-most-directory/, initialize a workspace
+lerna init
-Next, we will need to create the React component library that will wrap your Stencil components. This library will be a sibling to your Stencil component library. Inside your monorepo, you can create your own React project, or you can use the [React component library template](https://github.com/ionic-team/stencil-ds-react-template) to bootstrap it. To do this, run the following command
+# install dependencies
+npm install
-```bash
-git clone https://github.com/ionic-team/stencil-ds-react-template component-library-react
-cd component-library-react
-npm i
+# install typescript and node types
+npm install typescript @types/node --save-dev
```
+#### Creating a Stencil Component Library
+
:::note
-If you want to name your React component library something different, add the new name at the end of the clone command like so
+If you already have a Stencil component library, skip this section.
:::
-```bash
-git clone https://github.com/ionic-team/stencil-ds-react-template {the name of your React component library}
-cd {the name of your React component library}
-npm i
+From the `packages/` directory, run the following commands to create a Stencil component library:
+
+```bash npm2yarn
+npm init stencil components stencil-library
+cd stencil-library
+# Install dependencies
+npm install
```
-If you do rename your React component library, be sure to change the `name` in the `package.json` to match your new name.
+#### Creating a React Component Library
+
+:::note
+If you already have a React component library, skip this section.
+:::
-### Install the React Output Target in your Stencil Component Library
+The first time you want to create the component wrappers, you will need to have a React library package to write to.
-Now that the project structure is set up, we can install the React Output Target package in your Stencil component library. This package contains the React wrapper function that we will use to generate our React wrapped components inside a 'React component library'. To install the React Output Target package, run the following command in your **Stencil project directory**:
+Run the following commands from the root directory of your monorepo to create a React component library:
```bash npm2yarn
-npm install @stencil/react-output-target --save-dev
+# Create a project
+lerna create react-library # fill out the prompts accordingly
+cd packages/react-library
+
+# Install core dependencies
+npm install react react-dom typescript @types/react --save-dev
+```
+
+Lerna does not ship with a TypeScript configuration. At the root of the workspace, create a `tsconfig.json`:
+
+```json
+{
+ "compilerOptions": {
+ "module": "commonjs",
+ "declaration": true,
+ "noImplicitAny": false,
+ "removeComments": true,
+ "noLib": false,
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "target": "es6",
+ "sourceMap": true,
+ "lib": ["es6"]
+ },
+ "exclude": ["node_modules", "**/*.spec.ts", "**/__tests__/**"]
+}
```
-### Add the React Wrapper Function to your Stencil Component Library
+In your `react-library` project, create a project specific `tsconfig.json` that will extend the root config:
+
+```json
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "./dist",
+ "lib": ["dom", "es2015"],
+ "module": "es2015",
+ "moduleResolution": "node",
+ "target": "es2015",
+ "skipLibCheck": true,
+ "jsx": "react",
+ "allowSyntheticDefaultImports": true,
+ "declarationDir": "./dist/types"
+ },
+ "include": ["lib"],
+ "exclude": ["node_modules"]
+}
+```
-With the React Output Target package installed, we can now configure our Stencil component library to build our React wrapped components (within our React component library). In the `stencil.config.ts` file of your Stencil component library, add the React wrapper function
+Update the generated `package.json` in your `react-library`, adding the following options to the existing config:
+
+```diff
+{
+- "main": "lib/react-library.js",
++ "main": "dist/index.js",
++ "module": "dist/index.js",
++ "types": "dist/types/index.d.ts",
+ "scripts": {
+- "test": "test": "node ./__tests__/react-library.test.js"
++ "test": "test": "node ./__tests__/react-library.test.js",
++ "build": "npm run tsc",
++ "tsc": "tsc -p ."
+- }
++ },
+ "files": [
+- "lib"
++ "dist"
+ ]
++ "publishConfig": {
++ "access": "public"
++ },
++ "dependencies": {
++ "stencil-library": "*"
++ }
+}
+```
-```tsx
-import { Config } from '@stencil/core';
-import { reactOutputTarget as react } from '@stencil/react-output-target';
+:::note
+The `stencil-library` dependency is how Lerna knows to resolve the internal Stencil library dependency. See Lerna's documentation on
+[package dependency management](https://lerna.js.org/docs/getting-started#package-dependency-management) for more information.
+:::
+
+### Adding the React Output Target
+
+Install the `@stencil/react-output-target` dependency to your Stencil component library package.
+
+```bash npm2yarn
+# Install dependency
+npm install @stencil/react-output-target --save-dev
+```
+
+In your project's `stencil.config.ts`, add the `reactOutputTarget` configuration to the `outputTargets` array:
+
+```ts
+import { reactOutputTarget } from '@stencil/react-output-target';
export const config: Config = {
- ...
+ namespace: 'stencil-library',
outputTargets: [
- react({
- componentCorePackage: 'your-stencil-library-name',
- proxiesFile: '../your-react-library-name/src/components/stencil-generated/index.ts',
- includeDefineCustomElements: true,
- }),
+ // By default, the generated proxy components will
+ // leverage the output from the `dist` target, so we
+ // need to explicitly define that output alongside the
+ // React target
{
type: 'dist',
esmLoaderPath: '../loader',
},
- {
- type: 'dist-custom-elements',
- },
- ...
+ reactOutputTarget({
+ componentCorePackage: 'stencil-library',
+ proxiesFile: '../react-library/lib/components/stencil-generated/index.ts',
+ }),
],
};
```
-First, make sure to import the `reactOutputTarget` function from `@stencil/react-output-target` at the top of the file. With that imported, we can now use it in the `outputTargets` array and specify the relevant parameters. The `componentCorePackage` should be the name of your Stencil component library. The `proxiesFile` is the file that gets generated by the React wrapper function and contains the definitions of all the React wrapper components. Be sure to change the path names to reflect the names of your packages.
+:::tip
+The `proxiesFile` is the relative path to the file that will be generated with all of the React component wrappers. You will replace the
+file path to match your project's structure and respective names. You can generate any file name instead of `index.ts`.
+
+The `componentCorePackage` should match the `name` field in your Stencil project's `package.json`.
+:::
-For details on the `includeDefineCustomElements` option, and all other options, visit the API documentation section below.
+See the [API section below](#api) for details on each of the output target's options.
-With the `reactOutputTarget` configured, we can now generate our React wrapped components. In your **Stencil component library** run
+You can now build your Stencil component library to generate the component wrappers.
```bash npm2yarn
+# Build the library and wrappers
npm run build
```
-You’ll see the new generated file in your React component library at the location specified by the `proxiesFile` .
-
-```
-top-most-directory/
-├── stencil-library/
-│ ├── stencil.config.js
-│ └── src/components/
-└── react-library/
- └── src/
- └── components/
- │ └── stencil-generated/
- │ └── react-component-lib/
- │ └── index.ts <-- the newly generated file
- └── index.ts
-```
+If the build is successful, you’ll see the new generated file in your React component library at the location specified by the `proxiesFile` argument.
### Add the Components to your React Component Library's Entry File
-:::note
-If you are using our React template, this should already be prepared for you, and this step can be safely skipped.
-:::
-
-In order to make the generated files available within your React component library and its consumers, you’ll need to export everything from within your entry file - commonly the `src/index.ts` file. To do this, you’ll write:
+In order to make the generated files available within your React component library and its consumers, you’ll need to export everything from within your entry file. First, rename `react-library.js` to `index.ts`. Then, modify the contents to match the following:
```tsx
-export * from './components';
+export * from './components/stencil-generated';
```
-### Link Your Packages (Optional)
-
-If you want to build and test your components locally, you will need to link the packages together. This is a replacement for publishing packages to npm that allows you to develop and test locally. To do this, we’ll use the `npm link` command. This command creates a global symlink for a given package and thereby allows it to be consumed by other packages in your environment.
+### Registering Custom Elements
-First, build your Stencil component library. In your **Stencil component library**, run
+To register your web components for the lazy-loaded (hydrated) bundle, you'll need to expose a method for registering the underlying Stencil
+generated custom elements for the React proxy components to leverage. The easiest way to do this is to modify the React library's entry file
+to re-export the Stencil loader's `defineCustomElements()` method. In your React library's entry file (`packages/react-library/lib/index.ts`),
+add the following:
-```bash npm2yarn
-npm run build
+```diff
+export * from "./components/stencil-generated";
++ export { defineCustomElements } from "stencil-library/loader";
```
-Now you can create a symlink for your Stencil component library. From within your **Stencil component library**, run
+### Link Your Packages (Optional)
+
+:::note
+If you are using a monorepo tool (Lerna, Nx, etc.), skip this section.
+:::
+
+Before you can successfully build a local version of your React component library, you will need to link the Stencil package to the React package.
+
+From your Stencil project's directory, run the following command:
```bash npm2yarn
+# Link the working directory
npm link
```
-With the symlink created, we next need to specify which packages will be consuming them. Your React component library will need to consume your Stencil component library. In the directory of your **React component library** run
+From your React component library's directory, run the following command:
```bash npm2yarn
-npm link {Stencil library name}
+# Link the package name
+npm link name-of-your-stencil-package
```
-And with that, your component libraries are linked together. Now, you can make changes in your Stencil component library and run `npm run build` to propagate them through to the React component library without having to relink.
+The name of your Stencil package should match the `name` property from the Stencil component library's `package.json`.
+
+Your component libraries are now linked together. You can make changes in the Stencil component library and run `npm run build` to propagate the
+changes to the React component library.
+
+:::tip
+As an alternative to `npm link` , you can also run `npm install` with a relative path to your Stencil component library. This strategy, however, will
+modify your `package.json` so it is important to make sure you do not commit those changes.
+:::
+
+## Consumer Usage
+
+### Creating a Consumer React App
:::note
-As an alternative to `npm link` , you can also run `npm install` with a relative path to your Stencil component library. This strategy, however, will modify your `package.json` so it is important to make sure you do not commit those changes.
+If you already have a React app, skip this section.
:::
-## Usage
+From the `packages/` directory, run the following commands to create a starter React app:
-If you are developing and testing your React component library locally, you'll have to use `npm link` again to make your React component library available in your React application. If your components are published to npm, you can skip this step.
+
+
-To link your React component library, navigate to your **React component library** and run
+```bash
+# Create the React app
+npm create vite@latest my-app -- --template react-ts
+# of if using yarn
+yarn create vite my-app --template react-ts
-```bash npm2yarn
-npm run build
-npm link
+cd ./my-app
+
+# install dependencies
+npm install
+# or if using yarn
+yarn install
```
-To build your React component library and create a symlink to the project.
+You'll also need to link your React component library as a dependency. This step makes it so your React app will be able to correctly resolve imports from your React library. This
+is easily done by modifying your React app's `package.json` to include the following:
-Navigate to your **React application directory** and run
+```json
+"dependencies": {
+ "react-library": "*"
+}
+```
+
+### Consuming the React Wrapper Components
+
+This section covers how developers consuming your React component wrappers will use your package and component wrappers.
+
+Before you can consume your React proxy components, you'll need to build your React component library. From `packages/react-library` run:
```bash npm2yarn
-npm link {React component library}
+npm run build
```
To make use of your React component library in your React application, import your components from your React component library in the file where you want to use them.
```tsx
-// if your React component library has another name, replace 'component-library-react' with that name
-import { MyComponent } from 'component-library-react';
+// App.tsx
+import './App.css';
+import { MyComponent, defineCustomElements } from 'react-library';
+
+defineCustomElements();
+
+function App() {
+ return (
+
+
+
+ );
+}
+
+export default App;
```
-With that, your component is now available to be used like any other React component.
+## API
-## FAQ's
+### componentCorePackage
-### What is the best format to write event names?
+**Optional**
-Event names shouldn’t include special characters when initially written in Stencil. Try to lean on using camelCased event names for interoperability between frameworks.
+**Default: The `components.d.ts` file in the Stencil project's `package.json` types field**
-### How do I add IE11 or Edge support?
+**Type: `string`**
-:::info
-As of Stencil v3, legacy browser support is deprecated, and will be removed in a future major version of Stencil.
-:::
+The name of the Stencil package where components are available for consumers (i.e. the value of the `name` property in your Stencil component library's `package.json`).
+This is used during compilation to write the correct imports for components.
-If you want your custom elements to be able to work on older browsers, you should add the `applyPolyfills()` that surround the `defineCustomElements()` function.
+For a starter Stencil project generated by running:
-```tsx
-import { applyPolyfills, defineCustomElements } from 'test-components/loader';
+```bash npm2yarn
+npm init stencil component my-component-lib
+```
-applyPolyfills().then(() => {
- defineCustomElements();
-});
+The `componentCorePackage` would be set to:
+
+```ts
+// stencil.config.ts
+
+export const config: Config = {
+ ...,
+ outputTargets: [
+ reactOutputTarget({
+ componentCorePackage: 'my-component-lib',
+ // ... additional config options
+ })
+ ]
+}
```
-## API
+Which would result in an import path like:
+
+```js
+import { defineCustomElement as defineMyComponent } from 'my-component-lib/components/my-component.js';
+```
+
+:::note
+Although this field is optional, it is _highly_ recommended that it always be defined to avoid potential issues with paths not being generated correctly
+when combining other API arguments.
+:::
+
+### customElementsDir
+
+**Optional**
+
+**Default: 'dist/components'**
+
+**Type: `string`**
+
+If [includeImportCustomElements](#includeimportcustomelements) is `true`, this option can be used to specify the directory where the generated
+custom elements live. This value only needs to be set if the `dir` field on the `dist-custom-elements` output target was set to something other than
+the default directory.
+
+### excludeComponents
+
+**Optional**
+
+**Default: `[]`**
+
+**Type: `string[]`**
+
+This lets you specify component tag names for which you don't want to generate React wrapper components. This is useful if you need to write framework-specific versions of components. For instance, in Ionic Framework, this is used for routing components - like tabs - so that
+Ionic Framework can integrate better with React Router.
+
+### includeDefineCustomElements
+
+**Optional**
+
+**Default: `true`**
+
+**Type: `boolean`**
+
+If `true`, all Web Components will automatically be registered with the Custom Elements Registry. This can only be used when lazy loading Web Components and will not work when `includeImportCustomElements` is `true`.
+
+### includeImportCustomElements
+
+**Optional**
+
+**Default: `undefined`**
+
+**Type: `boolean`**
+
+If `true`, the output target will import the custom element instance and register it with the Custom Elements Registry when the component is imported inside of a user's app. This can only be used with the [Custom Elements](/docs/custom-elements) output and will not work with lazy loaded components.
+
+### includePolyfills
+
+**Optional**
+
+**Default: `true`**
+
+**Type: `boolean`**
+
+If `true`, polyfills will automatically be imported and the `applyPolyfills` function will be called in your proxies file. This can only be used when lazy loading Web Components and will not work when `includeImportCustomElements` is enabled.
+
+### loaderDir
+
+**Optional**
+
+**Default: `/dist/loader`**
+
+**Type: `string`**
+
+The path to where the `defineCustomElements` helper method exists within the built project. This option is only used when `includeDefineCustomElements` is enabled.
### proxiesFile
+**Required**
+
+**Type: `string`**
+
This parameter allows you to name the file that contains all the component wrapper definitions produced during the compilation process. This is the first file you should import in your React project.
-### includeDefineCustomElements
+## FAQ's
-If `true`, React components will import and define elements from the [`dist-custom-elements` build](/custom-elements), rather than [`dist`](/distribution).
+### Do I have to use the `dist` output target?
-### excludeComponents
+No! By default, this output target will look to use the `dist` output, but the output from `dist-custom-elements` can be used alternatively.
-This lets you exclude wrapping certain Web Components. This is useful if you need to write framework-specific versions of components. In Ionic Framework, this is used for routing components, like tabs, so that Ionic Framework can integrate better with React's Router.
+To do so, simply set the `includeImportCustomElements` option in the output target's config and ensure the
+[custom elements output target](/docs/custom-elements) is added to the Stencil config's output target array:
+
+```ts
+// stencil.config.ts
+
+export const config: Config = {
+ ...,
+ outputTargets: [
+ // Needs to be included
+ {
+ type: 'dist-custom-elements'
+ },
+ reactOutputTarget({
+ componentCorePackage: 'component-library',
+ proxiesFile: '{path to your proxy file}',
+ // This is what tells the target to use the custom elements output
+ includeImportCustomElements: true
+ })
+ ]
+}
+```
+
+Now, all generated imports will point to the default directory for the custom elements output. If you specified a different directory
+using the `dir` property for `dist-custom-elements`, you need to also specify that directory for the React output target. See
+[the API section](#customelementsdir) for more information.
+
+In addition, all the Web Components will be automatically defined as the generated component modules are bootstrapped.
+
+### What is the best format to write event names?
+
+Event names shouldn’t include special characters when initially written in Stencil. Try to lean on using camelCased event names for interoperability between frameworks.
+
+### How do I add IE11 or Edge support?
+
+If you want your custom elements to work on older browsers, you should call the `applyPolyfills()` function before `defineCustomCustomElements()`.
+`applyPolyfills()` returns a `Promise`, so you could call it like this:
+
+```tsx
+import { applyPolyfills, defineCustomElements } from 'test-components/loader';
+
+applyPolyfills().then(() => {
+ defineCustomElements();
+});
+```
diff --git a/versioned_docs/version-v2/framework-integration/react.md b/versioned_docs/version-v2/framework-integration/react.md
index a4ff7e2ba..5dd18875d 100644
--- a/versioned_docs/version-v2/framework-integration/react.md
+++ b/versioned_docs/version-v2/framework-integration/react.md
@@ -1,7 +1,7 @@
---
title: React Integration with Stencil
sidebar_label: React
-description: React Integration with Stencil
+description: Learn how to wrap your components so that people can use them natively in React
slug: /react
contributors:
- jthoms1
@@ -12,225 +12,507 @@ contributors:
- danawoodman
- a-giuliano
- rwaskiewicz
+ - tanner-reits
---
# React Integration
**Supports: React v16.7+ • TypeScript 3.7+ • Stencil v2.9.0+**
-Stencil provides a wrapper for your custom elements to be used as first-class React components. The goal of a wrapper is to easily integrate your Stencil components into a specific framework. Wrappers provide a function that you can use within Stencil’s Output Targets to automatically create components for the targeted framework that wrap the web components you create in a Stencil project.
+Stencil can generate React component wrappers for your web components. This allows your Stencil components to be used within
+a React application. The benefits of using Stencil's component wrappers over the standard web components include:
-One benefit of the wrapper pattern includes improved maintainability since you can write code once, and reuse it across different frameworks. Today, there are some challenges associated with using HTML Custom Elements in a React app. Custom events are not handled properly, as well as properties/attributes that are not a string or number. By using Stencil's component wrappers, you can solve these issues and receive first-class React components.
+- Custom events will be handled correctly and correctly propagate through the React render tree
+- Properties and attributes that are not a string or number will be correctly bound to the component
## Setup
### Project Structure
-To organize the generated component libraries for different frameworks, we recommend using a monorepo structure. This monorepo will contain your Stencil component library as well as the component libraries for whatever frameworks you choose. The overall structure of a monorepo with Stencil and React component libraries might look something like this
+We recommend using a [monorepo](https://www.toptal.com/front-end/guide-to-monorepos) structure for your component library with component
+wrappers. Your project workspace should contain your Stencil component library and the library for the generated React component wrappers.
+
+An example project set-up may look similar to:
```
top-most-directory/
-├── stencil-library/
-│ ├── stencil.config.js
-│ └── src/components/
-└── react-library/
- └── src/
- ├── components/
- └── index.ts
+└── packages/
+ ├── stencil-library/
+ │ ├── stencil.config.js
+ │ └── src/components/
+ └── react-library/
+ └── src/
+ ├── components/
+ └── index.ts
```
-To do this, start by creating a monorepo
+This guide uses Lerna for the monorepo, but you can use other solutions such as Nx, TurboRepo, etc.
-```bash
-mkdir {the name of your monorepo}
+To use Lerna with this walk through, globally install Lerna:
+
+```bash npm2yarn
+npm install --global lerna
```
-And then move your Stencil component library into your monorepo
+#### Creating a Monorepo
-```bash
-mv {the path to your Stencil component library} {the path to your monorepo}
-```
+:::note
+If you already have a monorepo, skip this section.
+:::
-### Create a React Component Library
+```bash npm2yarn
+# From your top-most-directory/, initialize a workspace
+lerna init
-Next, we will need to create the React component library that will wrap your Stencil components. This library will be a sibling to your Stencil component library. Inside your monorepo, you can create your own React project, or you can use the [React component library template](https://github.com/ionic-team/stencil-ds-react-template) to bootstrap it. To do this, run the following command
+# install dependencies
+npm install
-```bash
-git clone https://github.com/ionic-team/stencil-ds-react-template component-library-react
-cd component-library-react
-npm i
+# install typescript and node types
+npm install typescript @types/node --save-dev
```
+#### Creating a Stencil Component Library
+
:::note
-If you want to name your React component library something different, add the new name at the end of the clone command like so
+If you already have a Stencil component library, skip this section.
:::
-```bash
-git clone https://github.com/ionic-team/stencil-ds-react-template {the name of your React component library}
-cd {the name of your React component library}
-npm i
+From the `packages/` directory, run the following commands to create a Stencil component library:
+
+```bash npm2yarn
+npm init stencil components stencil-library
+cd stencil-library
+# Install dependencies
+npm install
```
-If you do rename your React component library, be sure to change the `name` in the `package.json` to match your new name.
+#### Creating a React Component Library
+
+:::note
+If you already have a React component library, skip this section.
+:::
-### Install the React Output Target in your Stencil Component Library
+The first time you want to create the component wrappers, you will need to have a React library package to write to.
-Now that the project structure is set up, we can install the React Output Target package in your Stencil component library. This package contains the React wrapper function that we will use to generate our React wrapped components inside a 'React component library'. To install the React Output Target package, run the following command in your **Stencil project directory**:
+Run the following commands from the root directory of your monorepo to create a React component library:
```bash npm2yarn
-npm install @stencil/react-output-target --save-dev
+# Create a project
+lerna create react-library # fill out the prompts accordingly
+cd packages/react-library
+
+# Install core dependencies
+npm install react react-dom typescript @types/react --save-dev
+```
+
+Lerna does not ship with a TypeScript configuration. At the root of the workspace, create a `tsconfig.json`:
+
+```json
+{
+ "compilerOptions": {
+ "module": "commonjs",
+ "declaration": true,
+ "noImplicitAny": false,
+ "removeComments": true,
+ "noLib": false,
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "target": "es6",
+ "sourceMap": true,
+ "lib": ["es6"]
+ },
+ "exclude": ["node_modules", "**/*.spec.ts", "**/__tests__/**"]
+}
```
-### Add the React Wrapper Function to your Stencil Component Library
+In your `react-library` project, create a project specific `tsconfig.json` that will extend the root config:
+
+```json
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "./dist",
+ "lib": ["dom", "es2015"],
+ "module": "es2015",
+ "moduleResolution": "node",
+ "target": "es2015",
+ "skipLibCheck": true,
+ "jsx": "react",
+ "allowSyntheticDefaultImports": true,
+ "declarationDir": "./dist/types"
+ },
+ "include": ["lib"],
+ "exclude": ["node_modules"]
+}
+```
-With the React Output Target package installed, we can now configure our Stencil component library to build our React wrapped components (within our React component library). In the `stencil.config.ts` file of your Stencil component library, add the React wrapper function
+Update the generated `package.json` in your `react-library`, adding the following options to the existing config:
+
+```diff
+{
+- "main": "lib/react-library.js",
++ "main": "dist/index.js",
++ "module": "dist/index.js",
++ "types": "dist/types/index.d.ts",
+ "scripts": {
+- "test": "test": "node ./__tests__/react-library.test.js"
++ "test": "test": "node ./__tests__/react-library.test.js",
++ "build": "npm run tsc",
++ "tsc": "tsc -p ."
+- }
++ },
+ "files": [
+- "lib"
++ "dist"
+ ]
++ "publishConfig": {
++ "access": "public"
++ },
++ "dependencies": {
++ "stencil-library": "*"
++ }
+}
+```
-```tsx
-import { Config } from '@stencil/core';
-import { reactOutputTarget as react } from '@stencil/react-output-target';
+:::note
+The `stencil-library` dependency is how Lerna knows to resolve the internal Stencil library dependency. See Lerna's documentation on
+[package dependency management](https://lerna.js.org/docs/getting-started#package-dependency-management) for more information.
+:::
+
+### Adding the React Output Target
+
+Install the `@stencil/react-output-target` dependency to your Stencil component library package.
+
+```bash npm2yarn
+# Install dependency
+npm install @stencil/react-output-target --save-dev
+```
+
+In your project's `stencil.config.ts`, add the `reactOutputTarget` configuration to the `outputTargets` array:
+
+```ts
+import { reactOutputTarget } from '@stencil/react-output-target';
export const config: Config = {
- ...
+ namespace: 'stencil-library',
outputTargets: [
- react({
- componentCorePackage: 'your-stencil-library-name',
- proxiesFile: '../your-react-library-name/src/components/stencil-generated/index.ts',
- includeDefineCustomElements: true,
- }),
+ // By default, the generated proxy components will
+ // leverage the output from the `dist` target, so we
+ // need to explicitly define that output alongside the
+ // React target
{
type: 'dist',
esmLoaderPath: '../loader',
},
- {
- type: 'dist-custom-elements',
- },
- ...
+ reactOutputTarget({
+ componentCorePackage: 'stencil-library',
+ proxiesFile: '../react-library/lib/components/stencil-generated/index.ts',
+ }),
],
};
```
-First, make sure to import the `reactOutputTarget` function from `@stencil/react-output-target` at the top of the file. With that imported, we can now use it in the `outputTargets` array and specify the relevant parameters. The `componentCorePackage` should be the name of your Stencil component library. The `proxiesFile` is the file that gets generated by the React wrapper function and contains the definitions of all the React wrapper components. Be sure to change the path names to reflect the names of your packages.
+:::tip
+The `proxiesFile` is the relative path to the file that will be generated with all of the React component wrappers. You will replace the
+file path to match your project's structure and respective names. You can generate any file name instead of `index.ts`.
+
+The `componentCorePackage` should match the `name` field in your Stencil project's `package.json`.
+:::
-For details on the `includeDefineCustomElements` option, and all other options, visit the API documentation section below.
+See the [API section below](#api) for details on each of the output target's options.
-With the `reactOutputTarget` configured, we can now generate our React wrapped components. In your **Stencil component library** run
+You can now build your Stencil component library to generate the component wrappers.
```bash npm2yarn
+# Build the library and wrappers
npm run build
```
-You’ll see the new generated file in your React component library at the location specified by the `proxiesFile` .
-
-```
-top-most-directory/
-├── stencil-library/
-│ ├── stencil.config.js
-│ └── src/components/
-└── react-library/
- └── src/
- └── components/
- │ └── stencil-generated/
- │ └── react-component-lib/
- │ └── index.ts <-- the newly generated file
- └── index.ts
-```
+If the build is successful, you’ll see the new generated file in your React component library at the location specified by the `proxiesFile` argument.
### Add the Components to your React Component Library's Entry File
-:::note
-If you are using our React template, this should already be prepared for you, and this step can be safely skipped.
-:::
-
-In order to make the generated files available within your React component library and its consumers, you’ll need to export everything from within your entry file - commonly the `src/index.ts` file. To do this, you’ll write:
+In order to make the generated files available within your React component library and its consumers, you’ll need to export everything from within your entry file. First, rename `react-library.js` to `index.ts`. Then, modify the contents to match the following:
```tsx
-export * from './components';
+export * from './components/stencil-generated';
```
-### Link Your Packages (Optional)
-
-If you want to build and test your components locally, you will need to link the packages together. This is a replacement for publishing packages to npm that allows you to develop and test locally. To do this, we’ll use the `npm link` command. This command creates a global symlink for a given package and thereby allows it to be consumed by other packages in your environment.
+### Registering Custom Elements
-First, build your Stencil component library. In your **Stencil component library**, run
+To register your web components for the lazy-loaded (hydrated) bundle, you'll need to expose a method for registering the underlying Stencil
+generated custom elements for the React proxy components to leverage. The easiest way to do this is to modify the React library's entry file
+to re-export the Stencil loader's `defineCustomElements()` method. In your React library's entry file (`packages/react-library/lib/index.ts`),
+add the following:
-```bash npm2yarn
-npm run build
+```diff
+export * from "./components/stencil-generated";
++ export { defineCustomElements } from "stencil-library/loader";
```
-Now you can create a symlink for your Stencil component library. From within your **Stencil component library**, run
+### Link Your Packages (Optional)
+
+:::note
+If you are using a monorepo tool (Lerna, Nx, etc.), skip this section.
+:::
+
+Before you can successfully build a local version of your React component library, you will need to link the Stencil package to the React package.
+
+From your Stencil project's directory, run the following command:
```bash npm2yarn
+# Link the working directory
npm link
```
-With the symlink created, we next need to specify which packages will be consuming them. Your React component library will need to consume your Stencil component library. In the directory of your **React component library** run
+From your React component library's directory, run the following command:
```bash npm2yarn
-npm link {Stencil library name}
+# Link the package name
+npm link name-of-your-stencil-package
```
-And with that, your component libraries are linked together. Now, you can make changes in your Stencil component library and run `npm run build` to propagate them through to the React component library without having to relink.
+The name of your Stencil package should match the `name` property from the Stencil component library's `package.json`.
+
+Your component libraries are now linked together. You can make changes in the Stencil component library and run `npm run build` to propagate the
+changes to the React component library.
+
+:::tip
+As an alternative to `npm link` , you can also run `npm install` with a relative path to your Stencil component library. This strategy, however, will
+modify your `package.json` so it is important to make sure you do not commit those changes.
+:::
+
+## Consumer Usage
+
+### Creating a Consumer React App
:::note
-As an alternative to `npm link` , you can also run `npm install` with a relative path to your Stencil component library. This strategy, however, will modify your `package.json` so it is important to make sure you do not commit those changes.
+If you already have a React app, skip this section.
:::
-## Usage
+From the `packages/` directory, run the following commands to create a starter React app:
-If you are developing and testing your React component library locally, you'll have to use `npm link` again to make your React component library available in your React application. If your components are published to npm, you can skip this step.
+
+
-To link your React component library, navigate to your **React component library** and run
+```bash
+# Create the React app
+npm create vite@latest my-app -- --template react-ts
+# of if using yarn
+yarn create vite my-app --template react-ts
-```bash npm2yarn
-npm run build
-npm link
+cd ./my-app
+
+# install dependencies
+npm install
+# or if using yarn
+yarn install
```
-To build your React component library and create a symlink to the project.
+You'll also need to link your React component library as a dependency. This step makes it so your React app will be able to correctly resolve imports from your React library. This
+is easily done by modifying your React app's `package.json` to include the following:
-Navigate to your **React application directory** and run
+```json
+"dependencies": {
+ "react-library": "*"
+}
+```
+
+### Consuming the React Wrapper Components
+
+This section covers how developers consuming your React component wrappers will use your package and component wrappers.
+
+Before you can consume your React proxy components, you'll need to build your React component library. From `packages/react-library` run:
```bash npm2yarn
-npm link {React component library}
+npm run build
```
To make use of your React component library in your React application, import your components from your React component library in the file where you want to use them.
```tsx
-// if your React component library has another name, replace 'component-library-react' with that name
-import { MyComponent } from 'component-library-react';
+// App.tsx
+import './App.css';
+import { MyComponent, defineCustomElements } from 'react-library';
+
+defineCustomElements();
+
+function App() {
+ return (
+
+
+
+ );
+}
+
+export default App;
```
-With that, your component is now available to be used like any other React component.
+## API
-## FAQ's
+### componentCorePackage
-### What is the best format to write event names?
+**Optional**
-Event names shouldn’t include special characters when initially written in Stencil. Try to lean on using camelCased event names for interoperability between frameworks.
+**Default: The `components.d.ts` file in the Stencil project's `package.json` types field**
-### How do I add IE11 or Edge support?
+**Type: `string`**
-If you want your custom elements to be able to work on older browsers, you should add the `applyPolyfills()` that surround the `defineCustomElements()` function.
+The name of the Stencil package where components are available for consumers (i.e. the value of the `name` property in your Stencil component library's `package.json`).
+This is used during compilation to write the correct imports for components.
-```tsx
-import { applyPolyfills, defineCustomElements } from 'test-components/loader';
+For a starter Stencil project generated by running:
-applyPolyfills().then(() => {
- defineCustomElements();
-});
+```bash npm2yarn
+npm init stencil component my-component-lib
```
-## API
+The `componentCorePackage` would be set to:
+
+```ts
+// stencil.config.ts
+
+export const config: Config = {
+ ...,
+ outputTargets: [
+ reactOutputTarget({
+ componentCorePackage: 'my-component-lib',
+ // ... additional config options
+ })
+ ]
+}
+```
+
+Which would result in an import path like:
+
+```js
+import { defineCustomElement as defineMyComponent } from 'my-component-lib/components/my-component.js';
+```
+
+:::note
+Although this field is optional, it is _highly_ recommended that it always be defined to avoid potential issues with paths not being generated correctly
+when combining other API arguments.
+:::
+
+### customElementsDir
+
+**Optional**
+
+**Default: 'dist/components'**
+
+**Type: `string`**
+
+If [includeImportCustomElements](#includeimportcustomelements) is `true`, this option can be used to specify the directory where the generated
+custom elements live. This value only needs to be set if the `dir` field on the `dist-custom-elements` output target was set to something other than
+the default directory.
+
+### excludeComponents
+
+**Optional**
+
+**Default: `[]`**
+
+**Type: `string[]`**
+
+This lets you specify component tag names for which you don't want to generate React wrapper components. This is useful if you need to write framework-specific versions of components. For instance, in Ionic Framework, this is used for routing components - like tabs - so that
+Ionic Framework can integrate better with React Router.
+
+### includeDefineCustomElements
+
+**Optional**
+
+**Default: `true`**
+
+**Type: `boolean`**
+
+If `true`, all Web Components will automatically be registered with the Custom Elements Registry. This can only be used when lazy loading Web Components and will not work when `includeImportCustomElements` is `true`.
+
+### includeImportCustomElements
+
+**Optional**
+
+**Default: `undefined`**
+
+**Type: `boolean`**
+
+If `true`, the output target will import the custom element instance and register it with the Custom Elements Registry when the component is imported inside of a user's app. This can only be used with the [Custom Elements](/docs/custom-elements) output and will not work with lazy loaded components.
+
+### includePolyfills
+
+**Optional**
+
+**Default: `true`**
+
+**Type: `boolean`**
+
+If `true`, polyfills will automatically be imported and the `applyPolyfills` function will be called in your proxies file. This can only be used when lazy loading Web Components and will not work when `includeImportCustomElements` is enabled.
+
+### loaderDir
+
+**Optional**
+
+**Default: `/dist/loader`**
+
+**Type: `string`**
+
+The path to where the `defineCustomElements` helper method exists within the built project. This option is only used when `includeDefineCustomElements` is enabled.
### proxiesFile
+**Required**
+
+**Type: `string`**
+
This parameter allows you to name the file that contains all the component wrapper definitions produced during the compilation process. This is the first file you should import in your React project.
-### includeDefineCustomElements
+## FAQ's
-If `true`, React components will import and define elements from the [`dist-custom-elements` build](/custom-elements), rather than [`dist`](/distribution).
+### Do I have to use the `dist` output target?
-### excludeComponents
+No! By default, this output target will look to use the `dist` output, but the output from `dist-custom-elements` can be used alternatively.
-This lets you exclude wrapping certain Web Components. This is useful if you need to write framework-specific versions of components. In Ionic Framework, this is used for routing components, like tabs, so that Ionic Framework can integrate better with React's Router.
+To do so, simply set the `includeImportCustomElements` option in the output target's config and ensure the
+[custom elements output target](/docs/custom-elements) is added to the Stencil config's output target array:
+
+```ts
+// stencil.config.ts
+
+export const config: Config = {
+ ...,
+ outputTargets: [
+ // Needs to be included
+ {
+ type: 'dist-custom-elements'
+ },
+ reactOutputTarget({
+ componentCorePackage: 'component-library',
+ proxiesFile: '{path to your proxy file}',
+ // This is what tells the target to use the custom elements output
+ includeImportCustomElements: true
+ })
+ ]
+}
+```
+
+Now, all generated imports will point to the default directory for the custom elements output. If you specified a different directory
+using the `dir` property for `dist-custom-elements`, you need to also specify that directory for the React output target. See
+[the API section](#customelementsdir) for more information.
+
+In addition, all the Web Components will be automatically defined as the generated component modules are bootstrapped.
+
+### What is the best format to write event names?
+
+Event names shouldn’t include special characters when initially written in Stencil. Try to lean on using camelCased event names for interoperability between frameworks.
+
+### How do I add IE11 or Edge support?
+
+If you want your custom elements to work on older browsers, you should call the `applyPolyfills()` function before `defineCustomCustomElements()`.
+`applyPolyfills()` returns a `Promise`, so you could call it like this:
+
+```tsx
+import { applyPolyfills, defineCustomElements } from 'test-components/loader';
+
+applyPolyfills().then(() => {
+ defineCustomElements();
+});
+```
diff --git a/versioned_docs/version-v3.0/framework-integration/react.md b/versioned_docs/version-v3.0/framework-integration/react.md
index 750ab6f15..5dd18875d 100644
--- a/versioned_docs/version-v3.0/framework-integration/react.md
+++ b/versioned_docs/version-v3.0/framework-integration/react.md
@@ -1,7 +1,7 @@
---
title: React Integration with Stencil
sidebar_label: React
-description: React Integration with Stencil
+description: Learn how to wrap your components so that people can use them natively in React
slug: /react
contributors:
- jthoms1
@@ -12,229 +12,507 @@ contributors:
- danawoodman
- a-giuliano
- rwaskiewicz
+ - tanner-reits
---
# React Integration
**Supports: React v16.7+ • TypeScript 3.7+ • Stencil v2.9.0+**
-Stencil provides a wrapper for your custom elements to be used as first-class React components. The goal of a wrapper is to easily integrate your Stencil components into a specific framework. Wrappers provide a function that you can use within Stencil’s Output Targets to automatically create components for the targeted framework that wrap the web components you create in a Stencil project.
+Stencil can generate React component wrappers for your web components. This allows your Stencil components to be used within
+a React application. The benefits of using Stencil's component wrappers over the standard web components include:
-One benefit of the wrapper pattern includes improved maintainability since you can write code once, and reuse it across different frameworks. Today, there are some challenges associated with using HTML Custom Elements in a React app. Custom events are not handled properly, as well as properties/attributes that are not a string or number. By using Stencil's component wrappers, you can solve these issues and receive first-class React components.
+- Custom events will be handled correctly and correctly propagate through the React render tree
+- Properties and attributes that are not a string or number will be correctly bound to the component
## Setup
### Project Structure
-To organize the generated component libraries for different frameworks, we recommend using a monorepo structure. This monorepo will contain your Stencil component library as well as the component libraries for whatever frameworks you choose. The overall structure of a monorepo with Stencil and React component libraries might look something like this
+We recommend using a [monorepo](https://www.toptal.com/front-end/guide-to-monorepos) structure for your component library with component
+wrappers. Your project workspace should contain your Stencil component library and the library for the generated React component wrappers.
+
+An example project set-up may look similar to:
```
top-most-directory/
-├── stencil-library/
-│ ├── stencil.config.js
-│ └── src/components/
-└── react-library/
- └── src/
- ├── components/
- └── index.ts
+└── packages/
+ ├── stencil-library/
+ │ ├── stencil.config.js
+ │ └── src/components/
+ └── react-library/
+ └── src/
+ ├── components/
+ └── index.ts
```
-To do this, start by creating a monorepo
+This guide uses Lerna for the monorepo, but you can use other solutions such as Nx, TurboRepo, etc.
-```bash
-mkdir {the name of your monorepo}
+To use Lerna with this walk through, globally install Lerna:
+
+```bash npm2yarn
+npm install --global lerna
```
-And then move your Stencil component library into your monorepo
+#### Creating a Monorepo
-```bash
-mv {the path to your Stencil component library} {the path to your monorepo}
-```
+:::note
+If you already have a monorepo, skip this section.
+:::
-### Create a React Component Library
+```bash npm2yarn
+# From your top-most-directory/, initialize a workspace
+lerna init
-Next, we will need to create the React component library that will wrap your Stencil components. This library will be a sibling to your Stencil component library. Inside your monorepo, you can create your own React project, or you can use the [React component library template](https://github.com/ionic-team/stencil-ds-react-template) to bootstrap it. To do this, run the following command
+# install dependencies
+npm install
-```bash
-git clone https://github.com/ionic-team/stencil-ds-react-template component-library-react
-cd component-library-react
-npm i
+# install typescript and node types
+npm install typescript @types/node --save-dev
```
+#### Creating a Stencil Component Library
+
:::note
-If you want to name your React component library something different, add the new name at the end of the clone command like so
+If you already have a Stencil component library, skip this section.
:::
-```bash
-git clone https://github.com/ionic-team/stencil-ds-react-template {the name of your React component library}
-cd {the name of your React component library}
-npm i
+From the `packages/` directory, run the following commands to create a Stencil component library:
+
+```bash npm2yarn
+npm init stencil components stencil-library
+cd stencil-library
+# Install dependencies
+npm install
```
-If you do rename your React component library, be sure to change the `name` in the `package.json` to match your new name.
+#### Creating a React Component Library
+
+:::note
+If you already have a React component library, skip this section.
+:::
-### Install the React Output Target in your Stencil Component Library
+The first time you want to create the component wrappers, you will need to have a React library package to write to.
-Now that the project structure is set up, we can install the React Output Target package in your Stencil component library. This package contains the React wrapper function that we will use to generate our React wrapped components inside a 'React component library'. To install the React Output Target package, run the following command in your **Stencil project directory**:
+Run the following commands from the root directory of your monorepo to create a React component library:
```bash npm2yarn
-npm install @stencil/react-output-target --save-dev
+# Create a project
+lerna create react-library # fill out the prompts accordingly
+cd packages/react-library
+
+# Install core dependencies
+npm install react react-dom typescript @types/react --save-dev
+```
+
+Lerna does not ship with a TypeScript configuration. At the root of the workspace, create a `tsconfig.json`:
+
+```json
+{
+ "compilerOptions": {
+ "module": "commonjs",
+ "declaration": true,
+ "noImplicitAny": false,
+ "removeComments": true,
+ "noLib": false,
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "target": "es6",
+ "sourceMap": true,
+ "lib": ["es6"]
+ },
+ "exclude": ["node_modules", "**/*.spec.ts", "**/__tests__/**"]
+}
```
-### Add the React Wrapper Function to your Stencil Component Library
+In your `react-library` project, create a project specific `tsconfig.json` that will extend the root config:
+
+```json
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "./dist",
+ "lib": ["dom", "es2015"],
+ "module": "es2015",
+ "moduleResolution": "node",
+ "target": "es2015",
+ "skipLibCheck": true,
+ "jsx": "react",
+ "allowSyntheticDefaultImports": true,
+ "declarationDir": "./dist/types"
+ },
+ "include": ["lib"],
+ "exclude": ["node_modules"]
+}
+```
-With the React Output Target package installed, we can now configure our Stencil component library to build our React wrapped components (within our React component library). In the `stencil.config.ts` file of your Stencil component library, add the React wrapper function
+Update the generated `package.json` in your `react-library`, adding the following options to the existing config:
+
+```diff
+{
+- "main": "lib/react-library.js",
++ "main": "dist/index.js",
++ "module": "dist/index.js",
++ "types": "dist/types/index.d.ts",
+ "scripts": {
+- "test": "test": "node ./__tests__/react-library.test.js"
++ "test": "test": "node ./__tests__/react-library.test.js",
++ "build": "npm run tsc",
++ "tsc": "tsc -p ."
+- }
++ },
+ "files": [
+- "lib"
++ "dist"
+ ]
++ "publishConfig": {
++ "access": "public"
++ },
++ "dependencies": {
++ "stencil-library": "*"
++ }
+}
+```
-```tsx
-import { Config } from '@stencil/core';
-import { reactOutputTarget as react } from '@stencil/react-output-target';
+:::note
+The `stencil-library` dependency is how Lerna knows to resolve the internal Stencil library dependency. See Lerna's documentation on
+[package dependency management](https://lerna.js.org/docs/getting-started#package-dependency-management) for more information.
+:::
+
+### Adding the React Output Target
+
+Install the `@stencil/react-output-target` dependency to your Stencil component library package.
+
+```bash npm2yarn
+# Install dependency
+npm install @stencil/react-output-target --save-dev
+```
+
+In your project's `stencil.config.ts`, add the `reactOutputTarget` configuration to the `outputTargets` array:
+
+```ts
+import { reactOutputTarget } from '@stencil/react-output-target';
export const config: Config = {
- ...
+ namespace: 'stencil-library',
outputTargets: [
- react({
- componentCorePackage: 'your-stencil-library-name',
- proxiesFile: '../your-react-library-name/src/components/stencil-generated/index.ts',
- includeDefineCustomElements: true,
- }),
+ // By default, the generated proxy components will
+ // leverage the output from the `dist` target, so we
+ // need to explicitly define that output alongside the
+ // React target
{
type: 'dist',
esmLoaderPath: '../loader',
},
- {
- type: 'dist-custom-elements',
- },
- ...
+ reactOutputTarget({
+ componentCorePackage: 'stencil-library',
+ proxiesFile: '../react-library/lib/components/stencil-generated/index.ts',
+ }),
],
};
```
-First, make sure to import the `reactOutputTarget` function from `@stencil/react-output-target` at the top of the file. With that imported, we can now use it in the `outputTargets` array and specify the relevant parameters. The `componentCorePackage` should be the name of your Stencil component library. The `proxiesFile` is the file that gets generated by the React wrapper function and contains the definitions of all the React wrapper components. Be sure to change the path names to reflect the names of your packages.
+:::tip
+The `proxiesFile` is the relative path to the file that will be generated with all of the React component wrappers. You will replace the
+file path to match your project's structure and respective names. You can generate any file name instead of `index.ts`.
+
+The `componentCorePackage` should match the `name` field in your Stencil project's `package.json`.
+:::
-For details on the `includeDefineCustomElements` option, and all other options, visit the API documentation section below.
+See the [API section below](#api) for details on each of the output target's options.
-With the `reactOutputTarget` configured, we can now generate our React wrapped components. In your **Stencil component library** run
+You can now build your Stencil component library to generate the component wrappers.
```bash npm2yarn
+# Build the library and wrappers
npm run build
```
-You’ll see the new generated file in your React component library at the location specified by the `proxiesFile` .
-
-```
-top-most-directory/
-├── stencil-library/
-│ ├── stencil.config.js
-│ └── src/components/
-└── react-library/
- └── src/
- └── components/
- │ └── stencil-generated/
- │ └── react-component-lib/
- │ └── index.ts <-- the newly generated file
- └── index.ts
-```
+If the build is successful, you’ll see the new generated file in your React component library at the location specified by the `proxiesFile` argument.
### Add the Components to your React Component Library's Entry File
-:::note
-If you are using our React template, this should already be prepared for you, and this step can be safely skipped.
-:::
-
-In order to make the generated files available within your React component library and its consumers, you’ll need to export everything from within your entry file - commonly the `src/index.ts` file. To do this, you’ll write:
+In order to make the generated files available within your React component library and its consumers, you’ll need to export everything from within your entry file. First, rename `react-library.js` to `index.ts`. Then, modify the contents to match the following:
```tsx
-export * from './components';
+export * from './components/stencil-generated';
```
-### Link Your Packages (Optional)
-
-If you want to build and test your components locally, you will need to link the packages together. This is a replacement for publishing packages to npm that allows you to develop and test locally. To do this, we’ll use the `npm link` command. This command creates a global symlink for a given package and thereby allows it to be consumed by other packages in your environment.
+### Registering Custom Elements
-First, build your Stencil component library. In your **Stencil component library**, run
+To register your web components for the lazy-loaded (hydrated) bundle, you'll need to expose a method for registering the underlying Stencil
+generated custom elements for the React proxy components to leverage. The easiest way to do this is to modify the React library's entry file
+to re-export the Stencil loader's `defineCustomElements()` method. In your React library's entry file (`packages/react-library/lib/index.ts`),
+add the following:
-```bash npm2yarn
-npm run build
+```diff
+export * from "./components/stencil-generated";
++ export { defineCustomElements } from "stencil-library/loader";
```
-Now you can create a symlink for your Stencil component library. From within your **Stencil component library**, run
+### Link Your Packages (Optional)
+
+:::note
+If you are using a monorepo tool (Lerna, Nx, etc.), skip this section.
+:::
+
+Before you can successfully build a local version of your React component library, you will need to link the Stencil package to the React package.
+
+From your Stencil project's directory, run the following command:
```bash npm2yarn
+# Link the working directory
npm link
```
-With the symlink created, we next need to specify which packages will be consuming them. Your React component library will need to consume your Stencil component library. In the directory of your **React component library** run
+From your React component library's directory, run the following command:
```bash npm2yarn
-npm link {Stencil library name}
+# Link the package name
+npm link name-of-your-stencil-package
```
-And with that, your component libraries are linked together. Now, you can make changes in your Stencil component library and run `npm run build` to propagate them through to the React component library without having to relink.
+The name of your Stencil package should match the `name` property from the Stencil component library's `package.json`.
+
+Your component libraries are now linked together. You can make changes in the Stencil component library and run `npm run build` to propagate the
+changes to the React component library.
+
+:::tip
+As an alternative to `npm link` , you can also run `npm install` with a relative path to your Stencil component library. This strategy, however, will
+modify your `package.json` so it is important to make sure you do not commit those changes.
+:::
+
+## Consumer Usage
+
+### Creating a Consumer React App
:::note
-As an alternative to `npm link` , you can also run `npm install` with a relative path to your Stencil component library. This strategy, however, will modify your `package.json` so it is important to make sure you do not commit those changes.
+If you already have a React app, skip this section.
:::
-## Usage
+From the `packages/` directory, run the following commands to create a starter React app:
-If you are developing and testing your React component library locally, you'll have to use `npm link` again to make your React component library available in your React application. If your components are published to npm, you can skip this step.
+
+
-To link your React component library, navigate to your **React component library** and run
+```bash
+# Create the React app
+npm create vite@latest my-app -- --template react-ts
+# of if using yarn
+yarn create vite my-app --template react-ts
-```bash npm2yarn
-npm run build
-npm link
+cd ./my-app
+
+# install dependencies
+npm install
+# or if using yarn
+yarn install
```
-To build your React component library and create a symlink to the project.
+You'll also need to link your React component library as a dependency. This step makes it so your React app will be able to correctly resolve imports from your React library. This
+is easily done by modifying your React app's `package.json` to include the following:
-Navigate to your **React application directory** and run
+```json
+"dependencies": {
+ "react-library": "*"
+}
+```
+
+### Consuming the React Wrapper Components
+
+This section covers how developers consuming your React component wrappers will use your package and component wrappers.
+
+Before you can consume your React proxy components, you'll need to build your React component library. From `packages/react-library` run:
```bash npm2yarn
-npm link {React component library}
+npm run build
```
To make use of your React component library in your React application, import your components from your React component library in the file where you want to use them.
```tsx
-// if your React component library has another name, replace 'component-library-react' with that name
-import { MyComponent } from 'component-library-react';
+// App.tsx
+import './App.css';
+import { MyComponent, defineCustomElements } from 'react-library';
+
+defineCustomElements();
+
+function App() {
+ return (
+
+
+
+ );
+}
+
+export default App;
```
-With that, your component is now available to be used like any other React component.
+## API
-## FAQ's
+### componentCorePackage
-### What is the best format to write event names?
+**Optional**
-Event names shouldn’t include special characters when initially written in Stencil. Try to lean on using camelCased event names for interoperability between frameworks.
+**Default: The `components.d.ts` file in the Stencil project's `package.json` types field**
-### How do I add IE11 or Edge support?
+**Type: `string`**
-:::info
-As of Stencil v3, legacy browser support is deprecated, and will be removed in a future major version of Stencil.
-:::
+The name of the Stencil package where components are available for consumers (i.e. the value of the `name` property in your Stencil component library's `package.json`).
+This is used during compilation to write the correct imports for components.
-If you want your custom elements to be able to work on older browsers, you should add the `applyPolyfills()` that surround the `defineCustomElements()` function.
+For a starter Stencil project generated by running:
-```tsx
-import { applyPolyfills, defineCustomElements } from 'test-components/loader';
+```bash npm2yarn
+npm init stencil component my-component-lib
+```
-applyPolyfills().then(() => {
- defineCustomElements();
-});
+The `componentCorePackage` would be set to:
+
+```ts
+// stencil.config.ts
+
+export const config: Config = {
+ ...,
+ outputTargets: [
+ reactOutputTarget({
+ componentCorePackage: 'my-component-lib',
+ // ... additional config options
+ })
+ ]
+}
```
-## API
+Which would result in an import path like:
+
+```js
+import { defineCustomElement as defineMyComponent } from 'my-component-lib/components/my-component.js';
+```
+
+:::note
+Although this field is optional, it is _highly_ recommended that it always be defined to avoid potential issues with paths not being generated correctly
+when combining other API arguments.
+:::
+
+### customElementsDir
+
+**Optional**
+
+**Default: 'dist/components'**
+
+**Type: `string`**
+
+If [includeImportCustomElements](#includeimportcustomelements) is `true`, this option can be used to specify the directory where the generated
+custom elements live. This value only needs to be set if the `dir` field on the `dist-custom-elements` output target was set to something other than
+the default directory.
+
+### excludeComponents
+
+**Optional**
+
+**Default: `[]`**
+
+**Type: `string[]`**
+
+This lets you specify component tag names for which you don't want to generate React wrapper components. This is useful if you need to write framework-specific versions of components. For instance, in Ionic Framework, this is used for routing components - like tabs - so that
+Ionic Framework can integrate better with React Router.
+
+### includeDefineCustomElements
+
+**Optional**
+
+**Default: `true`**
+
+**Type: `boolean`**
+
+If `true`, all Web Components will automatically be registered with the Custom Elements Registry. This can only be used when lazy loading Web Components and will not work when `includeImportCustomElements` is `true`.
+
+### includeImportCustomElements
+
+**Optional**
+
+**Default: `undefined`**
+
+**Type: `boolean`**
+
+If `true`, the output target will import the custom element instance and register it with the Custom Elements Registry when the component is imported inside of a user's app. This can only be used with the [Custom Elements](/docs/custom-elements) output and will not work with lazy loaded components.
+
+### includePolyfills
+
+**Optional**
+
+**Default: `true`**
+
+**Type: `boolean`**
+
+If `true`, polyfills will automatically be imported and the `applyPolyfills` function will be called in your proxies file. This can only be used when lazy loading Web Components and will not work when `includeImportCustomElements` is enabled.
+
+### loaderDir
+
+**Optional**
+
+**Default: `/dist/loader`**
+
+**Type: `string`**
+
+The path to where the `defineCustomElements` helper method exists within the built project. This option is only used when `includeDefineCustomElements` is enabled.
### proxiesFile
+**Required**
+
+**Type: `string`**
+
This parameter allows you to name the file that contains all the component wrapper definitions produced during the compilation process. This is the first file you should import in your React project.
-### includeDefineCustomElements
+## FAQ's
-If `true`, React components will import and define elements from the [`dist-custom-elements` build](/custom-elements), rather than [`dist`](/distribution).
+### Do I have to use the `dist` output target?
-### excludeComponents
+No! By default, this output target will look to use the `dist` output, but the output from `dist-custom-elements` can be used alternatively.
-This lets you exclude wrapping certain Web Components. This is useful if you need to write framework-specific versions of components. In Ionic Framework, this is used for routing components, like tabs, so that Ionic Framework can integrate better with React's Router.
+To do so, simply set the `includeImportCustomElements` option in the output target's config and ensure the
+[custom elements output target](/docs/custom-elements) is added to the Stencil config's output target array:
+
+```ts
+// stencil.config.ts
+
+export const config: Config = {
+ ...,
+ outputTargets: [
+ // Needs to be included
+ {
+ type: 'dist-custom-elements'
+ },
+ reactOutputTarget({
+ componentCorePackage: 'component-library',
+ proxiesFile: '{path to your proxy file}',
+ // This is what tells the target to use the custom elements output
+ includeImportCustomElements: true
+ })
+ ]
+}
+```
+
+Now, all generated imports will point to the default directory for the custom elements output. If you specified a different directory
+using the `dir` property for `dist-custom-elements`, you need to also specify that directory for the React output target. See
+[the API section](#customelementsdir) for more information.
+
+In addition, all the Web Components will be automatically defined as the generated component modules are bootstrapped.
+
+### What is the best format to write event names?
+
+Event names shouldn’t include special characters when initially written in Stencil. Try to lean on using camelCased event names for interoperability between frameworks.
+
+### How do I add IE11 or Edge support?
+
+If you want your custom elements to work on older browsers, you should call the `applyPolyfills()` function before `defineCustomCustomElements()`.
+`applyPolyfills()` returns a `Promise`, so you could call it like this:
+
+```tsx
+import { applyPolyfills, defineCustomElements } from 'test-components/loader';
+
+applyPolyfills().then(() => {
+ defineCustomElements();
+});
+```