How to create Electron app with Vite, Typescript, Tailwind and Shadcn UI

Development
Electron
Vite
Tailwind
Shadcn
Published on December 5, 2024, by Roman Ďurek

Creating a modern Electron app with all the latest tools and frameworks can be a challenging yet rewarding journey. When I first started this project, I struggled to find a guide that was both comprehensive and up-to-date. After countless hours of trial and error, I finally pieced together a workflow that works seamlessly. This post will walk you through the process step by step, spiced up with some reflections and tips.

Step 1: Starting with Electron and Vite

Electron is an amazing tool for building desktop apps using web technologies. But when you pair it with Vite and TypeScript, the magic really begins. Let’s dive in!

Start by creating your Electron app with Vite’s TypeScript template:

npm init electron-app@latest my-app -- --template=vite-typescript

cd my-app

Installing React

To bring the full power of React into the mix, install the necessary packages:

npm install --save-dev @types/react @types/react-dom react react-dom  @vitejs/plugin-react @types/node

Next, tweak your tsconfig.json file to enable JSX by adding this line:

{
  "compilerOptions": {
    "jsx": "react-jsx" // <== add this line
    // other configs
  }
}

Step 2: Setting Up the React Renderer

Creating a basic React setup in Electron requires just a few files. Let’s start by setting up the entry point for our app:

in src folder create app.tsx file

// # src/app.tsx

import "./index.css"; // import css

import * as React from "react";
import { createRoot } from "react-dom/client";

const root = createRoot(document.getElementById("root") as HTMLElement);
root.render(
  <React.StrictMode>
    <h1>Electron app with Vite, Typescript, Tailwind and Shadcn UI</h1>
  </React.StrictMode>,
);

in renderer.ts file add following lines:

// # src/renderer.ts

import "./index.css";
import "./app"; // <== add this line

Finally, modify your index.html file to serve the app:

<!-- # src/index.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Electron Vite TS Shadcn</title>
  </head>

  <body>
    <div id=""root"></"div>
    <script type="module" src="./src/renderer.ts"></script>
  </body>
</html>

Step 3: Updating Dependencies

At this point our should run with React installed with no problem, but Before moving forward, ensure that all dependencies are up-to-date. Run:

npm outdated

Updating your dependencies now will save you debugging headaches later. Once everything is green, you’re ready for the next step.

After updating all deprecated dependencies we can start our app, run

npm run start

If app is running, we can continue to install Tailwind and Shadcn UI components

Step 4: Adding Tailwind for Styling

Tailwind needs for installation file vite.config.ts otherwise it will fail on installation, so we have to create it in root folder of our app. We also wanna add following code into vite.renderer.config.ts.

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

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
});

Install Tailwind and its required dependencies:

npm install -D tailwindcss postcss autoprefixer

npx tailwindcss init -p

Add the base Tailwind directives to index.css file in src folder

@tailwind base;
@tailwind components;
@tailwind utilities;

Then configure Tailwind in tailwind.config.js

/* @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./index.html", "./src/*/*.{ts,tsx,js,jsx}"],
  theme: {
    extend: {},
  },
  plugins: [],
};

Edit tsconfig.json file, add baseUrl and paths under compilerOptions

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
    // other config
  }
}

That is all for Tailwind. Lets verify that everything still works. Add some styles in app.tsx file.

import "./index.css";

import * as React from "react";
import { createRoot } from "react-dom/client";

const root = createRoot(document.getElementById("root") as HTMLElement);
root.render(
  <React.StrictMode>
    <div className="min-h-screen bg-slate-600">
      <h1 className="text-4xl font-bold text-red-500">
        Electron app with Vite, Typescript, Tailwind and Shadcn UI
      </h1>
    </div>
  </React.StrictMode>,
);

Step 5: Introducing Shadcn UI Components

Shadcn UI components are a perfect complement to Tailwind. They provide pre-built, customizable components that look stunning. Begin by initializing Shadcn:

npx shadcn@latest init

Follow the prompts to configure Shadcn to your liking. Once the setup is complete, you can add your first component.

Which style would you like to use ? --Default
Which color would you like to use as the base color ? --Neutral
Would you like to use CSS variables for theming ? --yes

Sometimes it will messed up tailwind.config.js file, if you are using prettier just open file and press CTRL + S

Now let's add our first shadcn component

npx shadcn@latest add button

Button file will be automaticaly added to src/components/ui. Let's add it to our app.tsx file

import "./index.css";

import * as React from "react";
import { createRoot } from "react-dom/client";
import { Button } from "./components/ui/button";

const root = createRoot(document.getElementById("root") as HTMLElement);
root.render(
  <React.StrictMode>
    <div className="min-h-screen bg-slate-600">
      <h1 className="text-4xl font-bold text-red-500">
        Electron app with Vite, Typescript, Tailwind and Shadcn UI
      </h1>
      <Button>Submit</Button>
    </div>
  </React.StrictMode>,
);

Conclusion

Building an Electron app with Vite, TypeScript, Tailwind, and Shadcn UI is no small feat, but the result is a modern, highly customizable application. Each step in this guide is crafted to make the process as smooth as possible, with just enough flexibility for you to make it your own.

Now it’s your turn. Add more components, tweak the styles, and start building something amazing.

Happy coding! 🎉