Back to KB
Difficulty
Intermediate
Read Time
14 min

Build a VS Code Webview with React, Vite, Tailwind CSS, and VS Code-Themed Components

By Codcompass TeamΒ·Β·14 min read

This tutorial shows how to create a VS Code extension that opens a custom webview powered by:

  • React for the webview UI
  • Vite for fast frontend builds
  • Tailwind CSS for layout and custom styling
  • VS Code CSS theme variables for native-looking controls
  • VS Code Webview API for rendering the UI inside VS Code

1. Prerequisites

Install Node.js and npm first.

Then install the VS Code extension generator:

npm install --global yo generator-code

Enter fullscreen mode Exit fullscreen mode

You should also have VS Code installed.


2. Create the VS Code Extension

Run:

yo code

Enter fullscreen mode Exit fullscreen mode

Choose these options:

βœ” What type of extension do you want to create? New Extension (TypeScript)
βœ” What's the name of your extension? react-webview-vite
βœ” What's the identifier of your extension? react-webview-vite
βœ” What's the description of your extension? webview
βœ” Initialize a git repository? Yes
βœ” Which bundler to use? unbundled
βœ” Which package manager to use? npm

Enter fullscreen mode Exit fullscreen mode

This creates the extension shell where the important files are:

react-webview-vite/
  package.json
  src/
    extension.ts
  tsconfig.json

Enter fullscreen mode Exit fullscreen mode

Update the extension root tsconfig.json so the extension compiler only reads files from src/Β and does not accidentally compile the Vite React app inside webview-ui.

{
  "compilerOptions": {
    "module": "Node16",
    "target": "ES2022",
    "outDir": "out",
    "lib": ["ES2022"],
    "sourceMap": true,
    "rootDir": "src",
    "strict": true
  },
  "exclude": ["webview-ui"]
}

Enter fullscreen mode Exit fullscreen mode


3. Run the Extension for the First Time

Open the generated extension in VS Code. click on src/extension.ts

Press:

F5

Enter fullscreen mode Exit fullscreen mode

This starts the extension in a new window called the Extension Development Host.

In that new window:

  1. Open the Command Palette:
  • Windows: Ctrl + Shift + P
  • macOS: Cmd + Shift + P
    1. Run: Hello World

You should see the extension message: Hello World from react-webview-vite!

This confirms that the extension host works before adding React.


4. Add a React App with Vite

From the extension root, run the command below to create a React + TypeScript app inside a folder named webview-ui:

npm create vite@latest webview-ui

Enter fullscreen mode Exit fullscreen mode

Choose these options:

βœ” Select a framework? React
βœ” Select a variant? TypeScript

Enter fullscreen mode Exit fullscreen mode

Your project should now look like this:

react-webview-vite/
  src/
    extension.ts
  webview-ui/
    index.html
    package.json
    src/
      App.tsx
      main.tsx
      index.css
    vite.config.ts

Enter fullscreen mode Exit fullscreen mode


5. Install Tailwind CSS for Vite

To install dependencies:

cd webview-ui

Enter fullscreen mode Exit fullscreen mode

Inside webview-ui, install Tailwind using the Vite plugin:

npm install tailwindcss @tailwindcss/vite

Enter fullscreen mode Exit fullscreen mode

Update webview-ui/vite.config.ts:

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";

export default defineConfig({
  plugins: [react(), tailwindcss()],
  build: {
    outDir: "dist",
    emptyOutDir: true,
    rollupOptions: {
      output: {
        entryFileNames: "assets/[name].js",
        chunkFileNames: "assets/[name].js",
        assetFileNames: "assets/[name].[ext]",
      },
    },
  },
});

Enter fullscreen mode Exit fullscreen mode

Update webview-ui/src/index.css:

@import "tailwindcss";

:root {
  font-family: var(--vscode-font-family);
  color: var(--vscode-foreground);
  background: var(--vscode-editor-background);
}

body {
  margin: 0;
  min-width: 320px;
  min-height: 100vh;
  background: var(--vscode-editor-background);
  color: var(--vscode-foreground);
}

button,
input,
textarea,
select {
  font-family: inherit;
}

Enter fullscreen mode Exit fullscreen mode

This setup keeps Tailwind available while still respecting VS Code theme variables.


6. Create VS Code-Themed React Components

  • Build regular React components.
  • Style them with Tailwind.
  • Optionally use headless libraries like Radix UI if you need advanced accessible primitives such as dialogs, popovers, tabs, or dropdown menus.

Create webview-ui/src/components/vscode-ui.tsx:

import type {
  ButtonHTMLAttributes,
  InputHTMLAttributes,
  TextareaHTMLAttributes,
} from "react";

export function VSCodeButton({
  className = "",
  ...props
}: ButtonHTMLAttributes<HTMLButtonElement>) {
  return (
    <button
      className={`rounded px-3 py-1.5 text-sm font-medium text-[var(--vscode-button-foreground)] bg-[var(--vscode-button-background)] hover:bg-[var(--vscode-button-hoverBackground)] focus:outline focus:outline-1 focus:outline-[var(--vscode-focusBorder)] ${className}`}
      {...props}
    />
  );
}

export function VSCodeSecondaryButton({
  className = "",
  ...props
}: ButtonHTMLAttributes<HTMLButtonElement>) {
  return (
    <button
      className={`rounded px-3 py-1.5 text-sm font-medium text-[var(--vscode-button-secondaryForeground)] bg-[var(--vscode-button-secondaryBackground)] hover:bg-[var(--vscode-button-secondaryHoverBackground)] focus:outline focus:outline-1 focus:outline-[var(--vscode-focusBorder)] ${className}`}
      {...props}
    />
  );
}

export function VSCodeTextField({
  className = "",
  ...props
}: InputHTMLAttributes<HTMLInputElement>) {
  return (
    <input
      className={`w-full rounded border border-[var(--vscode-input-border)] bg-[var(--vscode-input-background)] px-3 py-2 text-sm text-[var(--vscode-input-foreground)] placeholder:text-[var(--vscode-input-placeholderForeground)] focus:outline focus:outline-1 focus:outline-[var(--vscode-focusBorder)] ${className}`}
      {...props}
    />
  );
}

export function VSCodeTextArea({
  className = "",
  ...props
}: TextareaHTMLAttributes<HTMLTextAreaElement>) {
  return (
    <textarea
      className={`min-h-24 w-full rounded border border-[var(--vscode-input-border)] bg-[var(--vscode-input-background)] px-3 py-2 text-sm text-[var(--vscode-input-foreground)] placeholder:text-[var(--vscode-input-placeholderForeground)] focus:outline focus:outline-1 fo

πŸŽ‰ Mid-Year Sale β€” Unlock Full Article

Base plan from just $4.99/mo or $49/yr

Sign in to read the full article and unlock all 635+ tutorials.

Sign In / Register β€” Start Free Trial

7-day free trial Β· Cancel anytime Β· 30-day money-back