---
title: "Bundling TinyMCE from a .zip package in React"
description: "A guide on bundling a .zip version of TinyMCE in a React project."
canonical_url: "https://www.tiny.cloud/docs/tinymce/latest/react-zip-bundle/"
md_url: "https://www.tiny.cloud/docs/tinymce/latest/react-zip-bundle/index.md"
version: "latest"
last_updated: "2026-01-19T04:37:32Z"
tokens: 1374
---
# Bundling TinyMCE from a .zip package in React

This shows how to self-host and bundle TinyMCE from a `.zip` package into a React application using the [TinyMCE React component](https://github.com/tinymce/tinymce-react).

## Prerequisites

This procedure requires [Node.js (and NPM)](https://nodejs.org/).

## Procedure

1. Use [Vite](https://github.com/vitejs/vite) and [React SWC](https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react-swc) to create a new React project named `tinymce-react-demo`.

```sh
# NPM 7+, extra double-dash is needed
npm create vite@5 tinymce-react-demo -- --template react-swc
```
2. Navigate to the project directory and install `@tinymce/tinymce-react`

```sh
cd tinymce-react-demo && npm install @tinymce/tinymce-react
```
3. Install `script-loader` package.

```sh
npm install script-loader
```
4. Unzip the content of the `tinymce/js` folder from the [TinyMCE zip](/my-account/downloads/) into the `src` folder.
5. Add `'src/tinymce'` to the `ignores` array to `+./eslint.config.js` file.

Diff of `.eslint.config.js`
```patch
diff --git a/eslint.config.js b/eslint.config.js
index 092408a..1ab8db4 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -5,7 +5,7 @@ import reactRefresh from 'eslint-plugin-react-refresh'
 import tseslint from 'typescript-eslint'

 export default tseslint.config(
-  { ignores: ['dist'] },
+  { ignores: ['dist', 'src/tinymce'] },
   {
     extends: [js.configs.recommended, ...tseslint.configs.recommended],
     files: ['**/*.{ts,tsx}'],
```
6. Install `vite-plugin-commonjs` and update `vite.config.ts` file to enable support for `CommonJS` modules.

```typescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import commonjs from 'vite-plugin-commonjs';

// https://vite.dev/config/
export default defineConfig({
  plugins: [react(), commonjs()],
});
```
7. Create `./src/BundledEditor.jsx` with the following code snippet:

```jsx
import { Editor } from '@tinymce/tinymce-react';
// Ensure to import `tinymce` first as other components expect
// a global variable `tinymce` to exist
import './tinymce/tinymce';
// DOM model
import './tinymce/models/dom/model'
// Theme
import './tinymce/themes/silver';
// Toolbar icons
import './tinymce/icons/default';
// Editor styles
import './tinymce/skins/ui/oxide/skin';
// Content styles, including inline UI like fake cursors
import './tinymce/skins/content/default/content';
import './tinymce/skins/ui/oxide/content';
// Import plugins
import './tinymce/plugins/anchor';
import './tinymce/plugins/advlist';
import './tinymce/plugins/autolink';
import './tinymce/plugins/charmap';
import './tinymce/plugins/code';
import './tinymce/plugins/media';
import './tinymce/plugins/visualblocks';
import './tinymce/plugins/fullscreen';
import './tinymce/plugins/insertdatetime';
import './tinymce/plugins/preview';
import './tinymce/plugins/help';
// Include resources that a plugin lazy-loads at the run-time
import './tinymce/plugins/help/js/i18n/keynav/en';
import './tinymce/plugins/image';
import './tinymce/plugins/link';
import './tinymce/plugins/lists';
import './tinymce/plugins/searchreplace';
import './tinymce/plugins/table';
import './tinymce/plugins/wordcount';

export default function BundledEditor(props) {
  return (
    <Editor
      licenseKey='gpl'
      {...props}
    />
  );
}
```
8. Add `BundleEditor` component with configuration into `App.jsx`.

```jsx
import { useRef } from 'react';
import BundledEditor from './BundledEditor'
import './App.css';

export default function App() {
  const editorRef = useRef(null);
  const log = () => {
    if (editorRef.current) {
      console.log(editorRef.current.getContent());
    }
  };
  return (
    <>
      <BundledEditor
        onInit={(_evt, editor) => editorRef.current = editor}
        initialValue='<p>This is the initial content of the editor.</p>'
        init={{
          height: 500,
          menubar: false,
          plugins: [
            'advlist', 'autolink', 'lists', 'link', 'image', 'charmap',
            'anchor', 'searchreplace', 'visualblocks', 'code', 'fullscreen',
            'insertdatetime', 'media', 'table', 'preview', 'help', 'wordcount'
          ],
          toolbar: 'undo redo | blocks | ' +
            'bold italic forecolor | alignleft aligncenter ' +
            'alignright alignjustify | bullist numlist outdent indent | ' +
            'removeformat | help',
          content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }'
        }}
      />
      <button onClick={log}>Log editor content</button>
    </>
  );
}
```
9. Run the development server to test the application:

```sh
npm run dev
```

## Other resources

- For information on bundling, see: [Introduction to bundling TinyMCE](../introduction-to-bundling-tinymce/)
- For examples of the TinyMCE React integration, see: [the tinymce-react storybook](https://tinymce.github.io/tinymce-react/).
- For guides on integrating TinyMCE premium plugins, see: [Using premium plugins](../bundling-plugins/#using-premium-plugins).
- For information on customizing:

  - TinyMCE integration, see: [TinyMCE React integration technical reference](../react-ref/).
  - TinyMCE, see: [Basic setup](../basic-setup/).
  - The React application, see: [Getting Started with Vite](https://vitejs.dev/guide/#getting-started) or [the React documentation](https://react.dev/learn).
