# How to Override the Default New Tab Page in Chrome Extensions

> Learn how to override Chrome's default new tab page with your own custom page using Chrome extensions. Follow this guide to build a personalized browsing experience.

- 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

---

**You can override the default new tab page by declaring a `chrome_url_overrides.newtab` entry in your extension manifest and pointing it to a custom HTML bundle built with Vite and React.**

The `jonghakseo/chrome-extension-boilerplate-react-vite` repository provides a complete, production-ready implementation of this pattern. By leveraging the `chrome_url_overrides` API alongside a dedicated Vite build pipeline, you can override the default new tab page with a fully customized React component that compiles to a static bundle Chrome loads instantly.

## How the New Tab Override Works

Chrome extensions replace built-in pages through the `chrome_url_overrides` manifest field. In this boilerplate, the override is wired across three architectural layers: the manifest declaration, the Vite build configuration, and the React source component.

### Manifest Declaration

The entry point for the override is defined in [`chrome-extension/manifest.ts`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/chrome-extension/manifest.ts) at lines 44–46. This tells Chrome to load your custom page instead of its default new tab interface:

```typescript
// chrome-extension/manifest.ts (lines 44-46)
chrome_url_overrides: {
  newtab: 'new-tab/index.html',
},

```

### Vite Build Pipeline

The custom page is built as a separate Vite entry point located at `pages/new-tab/vite.config.mts`. This configuration outputs the bundled assets to `dist/new-tab/`, ensuring the final [`index.html`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/index.html) path matches the manifest declaration exactly:

```typescript
// pages/new-tab/vite.config.mts
// Configures output to dist/new-tab/index.html

```

### React Component Source

The UI layer lives in [`pages/new-tab/src/NewTab.tsx`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/pages/new-tab/src/NewTab.tsx). This React component renders the actual content users see when opening a new tab. The module is registered under the package name `@extension/new-tab` in [`pages/new-tab/package.json`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/pages/new-tab/package.json), which the monorepo build system uses to resolve dependencies.

When you run `npm run build`, Vite compiles [`pages/new-tab/src/NewTab.tsx`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/pages/new-tab/src/NewTab.tsx) into [`dist/new-tab/index.html`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/dist/new-tab/index.html). Chrome then serves this file automatically whenever the user opens a new tab, requiring no additional runtime code or background script logic.

## Customizing Your New Tab Page

You can modify the override behavior by editing the React component, adding static assets, or adjusting the build configuration.

### Edit the React Component

Open [`pages/new-tab/src/NewTab.tsx`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/pages/new-tab/src/NewTab.tsx) to change the layout, styling, or functionality. The component exports a default function that returns JSX, which becomes the root of your new tab page.

Here is a practical example that replaces the default placeholder with a personalized greeting:

```tsx
// pages/new-tab/src/NewTab.tsx
import React from 'react';
import './NewTab.css'; // Add your own styles here

export default function NewTab() {
  const [name, setName] = React.useState('Friend');

  return (
    <div className="new-tab-root">
      <h1>Welcome, {name}!</h1>
      <p>This is your custom new tab page.</p>

      <input
        placeholder="Enter your name"
        onChange={e => setName(e.target.value)}
      />
    </div>
  );
}

```

### Add Static Assets

Place images, fonts, or additional CSS files inside `pages/new-tab/public/`. Create the folder if it does not exist. Vite automatically copies these files to `dist/new-tab/` during the build, allowing you to reference them with relative paths in your code.

### Build and Reload

After making changes, rebuild the extension to regenerate the `dist/new-tab/` bundle:

```bash
npm run build

```

Or use `pnpm build` if you are using pnpm. Once the build completes, navigate to `chrome://extensions`, click **Reload** on your development extension, and open a new tab to see your custom UI.

## Summary

- **Manifest configuration**: The override is declared in [`chrome-extension/manifest.ts`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/chrome-extension/manifest.ts) using `chrome_url_overrides.newtab` pointing to [`new-tab/index.html`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/new-tab/index.html).
- **Build pipeline**: `pages/new-tab/vite.config.mts` compiles the React source into [`dist/new-tab/index.html`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/dist/new-tab/index.html), matching the manifest path.
- **Source location**: The React component lives at [`pages/new-tab/src/NewTab.tsx`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/pages/new-tab/src/NewTab.tsx) and is registered under `@extension/new-tab`.
- **Customization**: Edit the React component, place assets in `pages/new-tab/public/`, rebuild with `npm run build`, and reload the extension to apply changes.

## Frequently Asked Questions

### Which manifest field declares the new tab override?

The `chrome_url_overrides.newtab` field in [`chrome-extension/manifest.ts`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/chrome-extension/manifest.ts) (lines 44–46) tells Chrome to load your custom page instead of the default new tab interface. It must point to the relative path [`new-tab/index.html`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/new-tab/index.html), which maps to the Vite output directory.

### Can I use vanilla JavaScript instead of React for the new tab page?

The boilerplate is configured for React in [`pages/new-tab/src/NewTab.tsx`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/pages/new-tab/src/NewTab.tsx) and `pages/new-tab/vite.config.mts`. While you could theoretically modify the Vite configuration to use a vanilla JavaScript entry point, the repository is designed around React components for consistency with the rest of the monorepo architecture.

### Where should I place images and fonts for the new tab page?

Place static assets inside `pages/new-tab/public/`. Vite automatically copies files from this directory to `dist/new-tab/` during the build process, allowing you to reference them with relative URLs in your React components or CSS files.

### Why is my custom new tab page not appearing after building?

Ensure you have reloaded the extension from `chrome://extensions` after running `npm run build`. Chrome caches extension resources aggressively, and the manifest changes in [`chrome-extension/manifest.ts`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/chrome-extension/manifest.ts) only take effect after a full reload. Also verify that [`dist/new-tab/index.html`](https://github.com/jonghakseo/chrome-extension-boilerplate-react-vite/blob/main/dist/new-tab/index.html) exists and matches the path declared in the manifest.