# How to Create a Side Panel for Chrome Extensions Using the React-Vite Boilerplate

> Learn to create a Chrome extension side panel with the React Vite boilerplate. Modify manifest and React components for quick activation.

- Repository: [JongHak Seo/chrome-extension-boilerplate-react-vite](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite)
- Tags: how-to-guide
- Published: 2026-03-05

---

**The jonghakseo/chrome-extension-boilerplate-react-vite ships with a pre-configured side panel that requires only manifest verification and React component customization to activate.**

The jonghakseo/chrome-extension-boilerplate-react-vite repository provides a complete, production-ready side panel implementation using React and Vite. To create a side panel for Chrome extensions with this boilerplate, you work within the existing `pages/side-panel` directory structure, customizing the React component while the build system handles Chrome manifest compliance and bundling automatically.

## Understanding the Side Panel Architecture

The side panel implementation consists of three integrated layers that handle Chrome API compliance, UI rendering, and build optimization.

### Manifest Declaration

Chrome requires explicit permission and path configuration to enable side panel functionality. In [`chrome-extension/manifest.ts`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/chrome-extension/manifest.ts), the boilerplate declares the `side_panel` field alongside the necessary permission:

```typescript
side_panel: {
  default_path: 'side-panel/index.html',
},
permissions: ['sidePanel']

```

This tells Chrome to load [`side-panel/index.html`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/side-panel/index.html) from the extension's distribution folder when the user opens the side panel.

### Page Assets

The UI layer resides in `pages/side-panel/` and follows standard React patterns:

- **HTML entry**: [`pages/side-panel/index.html`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/pages/side-panel/index.html) provides the DOM mount point (`#app-container`)
- **Bootstrap script**: [`pages/side-panel/src/index.tsx`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/pages/side-panel/src/index.tsx) creates the React root and renders the component
- **UI component**: [`pages/side-panel/src/SidePanel.tsx`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/pages/side-panel/src/SidePanel.tsx) contains the actual React implementation

### Build Configuration

The `pages/side-panel/vite.config.mts` file extends the shared `withPageConfig` helper from [`packages/vite-config/lib/with-page-config.ts`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/packages/vite-config/lib/with-page-config.ts). This configuration compiles TypeScript and React using SWC, outputs assets to `dist/side-panel` (matching the manifest path), excludes Chrome API from bundling, and applies Node polyfills for extension compatibility.

## Customizing the Side Panel Component

Follow these steps to modify the existing side panel or create additional panels.

1. **Verify manifest configuration**: Confirm [`chrome-extension/manifest.ts`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/chrome-extension/manifest.ts) includes `permissions: ['sidePanel']` and that `side_panel.default_path` points to your HTML file (default: `'side-panel/index.html'`).

2. **Modify the React component**: Edit [`pages/side-panel/src/SidePanel.tsx`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/pages/side-panel/src/SidePanel.tsx) or create a new component. The boilerplate provides shared hooks like `useStorage` and UI components from `@extension/ui` for consistent state management across extension surfaces.

3. **Update the entry point**: If you rename the component, modify [`pages/side-panel/src/index.tsx`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/pages/side-panel/src/index.tsx) to import and render your new component into the `#app-container` element.

4. **Apply styling**: Tailwind CSS is pre-configured. Add utility classes directly in components or import custom CSS files via `import '@src/CustomStyles.css';`.

5. **Test locally**: Run `pnpm dev` to start the Vite development server. Load the unpacked extension from `dist/` in Chrome, then open the side panel via the toolbar button's context menu or Chrome's side panel UI.

6. **Build for production**: Execute `pnpm build` to generate optimized assets in `dist/side-panel/` that Chrome serves when the panel opens.

## Code Implementation Examples

### Creating a Custom Side Panel Component

Replace or extend [`pages/side-panel/src/SidePanel.tsx`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/pages/side-panel/src/SidePanel.tsx) with your own implementation:

```typescript
// File: pages/side-panel/src/MySidePanel.tsx
import '@src/MySidePanel.css';
import { useStorage } from '@extension/shared';
import { exampleThemeStorage } from '@extension/storage';
import { cn, ToggleButton } from '@extension/ui';

const MySidePanel = () => {
  const { isLight } = useStorage(exampleThemeStorage);
  const logo = isLight ? 'side-panel/logo_vertical.svg' : 'side-panel/logo_vertical_dark.svg';

  return (
    <div className={cn('App', isLight ? 'bg-slate-50' : 'bg-gray-800')}>
      <header className={cn('App-header', isLight ? 'text-gray-900' : 'text-gray-100')}>
        <img src={chrome.runtime.getURL(logo)} className="App-logo" alt="logo" />
        <p>Welcome to my custom side panel!</p>
        <ToggleButton onClick={exampleThemeStorage.toggle}>Toggle Theme</ToggleButton>
      </header>
    </div>
  );
};

export default MySidePanel;

```

### Wiring the Component to the Entry Script

Update [`pages/side-panel/src/index.tsx`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/pages/side-panel/src/index.tsx) to mount your custom component:

```typescript
// File: pages/side-panel/src/index.tsx
import '@src/index.css';
import MySidePanel from '@src/MySidePanel';
import { createRoot } from 'react-dom/client';

const app = document.querySelector('#app-container');
if (!app) throw new Error('Missing #app-container');

createRoot(app).render(<MySidePanel />);

```

### Adjusting the Manifest Path

If you change the output directory or HTML filename, update [`chrome-extension/manifest.ts`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/chrome-extension/manifest.ts):

```typescript
side_panel: {
  default_path: 'my-custom-panel/index.html',
},

```

Ensure the Vite config's `outDir` in `pages/side-panel/vite.config.mts` corresponds to this path within the `dist` folder.

## Summary

- The boilerplate includes a complete side panel setup in `pages/side-panel/` with manifest declarations, React components, and Vite configuration.
- **Manifest configuration** in [`chrome-extension/manifest.ts`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/chrome-extension/manifest.ts) requires the `sidePanel` permission and `side_panel.default_path` pointing to the built HTML file.
- **Build integration** via `withPageConfig` outputs to `dist/side-panel`, ensuring Chrome loads the correct assets.
- **Development workflow** uses standard React patterns with `pnpm dev` for live reloading and `pnpm build` for production bundling.
- Shared utilities from `@extension/shared` and `@extension/ui` provide consistent state management and styling across the side panel and other extension pages.

## Frequently Asked Questions

### Does this boilerplate support multiple side panels?

Chrome extensions currently support only one side panel per extension at a time. You can dynamically change the panel's content using React Router or conditional rendering within the single [`SidePanel.tsx`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/SidePanel.tsx) component, but you cannot declare multiple `side_panel` entries in the manifest.

### How do I access Chrome storage from the side panel?

Use the `useStorage` hook from `@extension/shared` as demonstrated in the boilerplate's [`SidePanel.tsx`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/SidePanel.tsx). This hook synchronizes with the `exampleThemeStorage` or any custom storage module you define in the storage package, providing reactive state across the popup, content scripts, and side panel.

### Why does my side panel show a blank screen after building?

Verify that `pages/side-panel/vite.config.mts` outputs to the correct directory (`../../dist/side-panel` by default) and that [`chrome-extension/manifest.ts`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/chrome-extension/manifest.ts) references the correct relative path ([`side-panel/index.html`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/side-panel/index.html)). A mismatch between the Vite `outDir` and the manifest `default_path` causes Chrome to fail loading the panel assets.

### Can I use TypeScript path aliases in the side panel?

Yes. The boilerplate configures path aliases like `@src` and `@extension/ui` in the Vite configuration and TypeScript base configuration. These aliases work consistently across the side panel, popup, and options pages, allowing clean imports of shared components and utilities.