A modern Electron application template with React, Vite, TypeScript, and TailwindCSS. This project provides a solid foundation for developing cross-platform desktop applications.
🔹 Electron - Cross-platform desktop application framework.
🔹 React - Component-based UI library.
🔹 TypeScript - Type-safe JavaScript.
🔹 Shadcn UI - Beautiful and accessible component library.
🔹 TailwindCSS - Utility-first CSS framework.
🔹 Electron Vite - Lightning-fast build tool based on Vite for fastest hot-reload.
🔹 Electron Builder - Configured for packaging applications.
🔹 Conveyor - Type-safe inter-process communication with Zod validation.
🔹 Custom Window Titlebar & Menus - Style the window titlebar and menus as you want.
🔹 Clean Project Structure - Separation of main and renderer processes.
🔹 Resources Protocol - Access resources folder via res://
protocol.
🔹 Import path aliases – Keep your imports organized and clean.
🔹 Theme Switcher - Built-in theme switching for dark and light mode.
🔹 Error Boundary - Built-in React error boundary with detailed error reporting.
🔹 Welcome Kit - Interactive showcase with Framer Motion animations.
🔹 Code Formatting - Prettier and ESLint pre-configured for code quality.
🔹 Hot Reload - Lightning-fast development with Vite's HMR.
🔹 VS Code Debugging - Pre-configured launch configurations for debugging main and renderer processes.
Clone the repository:
# Clone the repository
git clone https://github.com/guasam/electron-react-app
# Change directory
cd electron-react-app
# Install dependencies (use any package manager: npm, yarn, pnpm, bun)
npm install
Start the development server:
npm run dev
This will start Electron with hot-reload enabled so you can see changes in real time.
Build the application for your platform:
# For Windows
npm run build:win
# For macOS
npm run build:mac
# For Linux
npm run build:linux
# Unpacked for all platforms
npm run build:unpack
Distribution files will be located in the dist
directory.
This project implements Conveyor, a type-safe IPC (Inter-Process Communication) system using Zod schemas for runtime validation. Conveyor provides a clean, modular API interface between the renderer and main processes with full TypeScript support.
📖 For detailed Conveyor documentation and advanced usage instructions, see its README
// In your React component
import { useEffect, useState } from 'react'
import { useConveyor } from '@/app/hooks/use-conveyor'
function AppInfo() {
const [version, setVersion] = useState<string>('')
const conveyor = useConveyor()
useEffect(() => {
// Get app version from main process
conveyor.app.version().then(setVersion)
}, [])
const handleMinimize = () => {
conveyor.window.windowMinimize()
}
const handleOpenUrl = (url: string) => {
conveyor.window.webOpenUrl(url)
}
return (
<div>
<p>App Version: {version}</p>
<button onClick={handleMinimize}>Minimize</button>
<button onClick={() => handleOpenUrl('https://github.com')}>Open GitHub</button>
</div>
)
}
The IPC system exposes several APIs through:
- global window object
window.conveyor
- react hook
useConveyor()
To add a new IPC channel, follow these steps:
Create or update a schema file in lib/conveyor/schemas/
:
// lib/ipc/schemas/app-schema.ts
import { z } from 'zod'
export const appIpcSchema = {
version: {
args: z.tuple([]),
return: z.string(),
},
'get-user-data': {
args: z.tuple([z.string()]), // userId parameter
return: z.object({
id: z.string(),
name: z.string(),
email: z.string().email(),
}),
},
'save-data': {
args: z.tuple([
z.object({
key: z.string(),
value: z.unknown(),
}),
]),
return: z.boolean(),
},
} as const
Update the corresponding API class in lib/conveyor/api/
:
// lib/conveyor/api/app-api.ts
import { ConveyorApi } from '@/lib/preload/shared'
export class AppApi extends ConveyorApi {
version = () => this.invoke('version')
getUserData = (userId: string) => this.invoke('get-user-data', userId)
saveData = (key: string, value: unknown) => this.invoke('save-data', { key, value })
}
Add the handler in lib/conveyor/handlers/
:
// lib/conveyor/handlers/app-handler.ts
import { handle } from '@/lib/main/shared'
import { app } from 'electron'
export const registerAppHandlers = () => {
handle('version', () => app.getVersion())
handle('get-user-data', async (userId: string) => {
// Your logic here
return {
id: userId,
name: 'John Doe',
email: 'john@example.com',
}
})
handle('save-data', async ({ key, value }) => {
// Your logic here
console.log(`Saving ${key}:`, value)
return true
})
}
Update lib/main/app.ts
to register your handlers:
import { registerAppHandlers } from '@/lib/conveyor/handlers/app-handler'
// In your app initialization
registerAppHandlers()
The IPC system provides full TypeScript support with runtime validation:
// TypeScript will enforce correct types
const userData = await conveyor.app.getUserData('123') // ✅ Correct
const userData = await conveyor.app.getUserData(123) // ❌ Type error
// Runtime validation ensures data integrity
const result = await conveyor.app.saveData('config', { theme: 'dark' })
try {
const data = await conveyor.app.getUserData('invalid-id')
} catch (error) {
console.error('IPC call failed:', error)
// Handle validation errors, network issues, etc.
}
This template includes a custom window implementation with:
- Custom titlebar with app icon
- Window control buttons (minimize, maximize, close)
- Menu system with keyboard shortcuts
- Dark/light mode toggle
- Cross-platform support for Windows and macOS
The titlebar menu can be toggled using:
- Windows: Press the
Alt
key - macOS: Press the
Option (⌥)
key
When you press the toggle key:
- If the menu is hidden, it becomes visible
- If the menu is already visible, it gets hidden
- The menu only toggles if menu items are available
To add, remove or modify menu items, update the following file:
app/components/window/menus.ts
The project supports Tailwind for styling:
// Example component with Tailwind classes
const Button = () => (
<button className="px-4 py-2 text-white rounded-md">
Click me
</button>
);
- React application that runs in the browser window
- Contains all UI components, styles, and client-side logic
- Uses Vite for fast development and building
- Type-safe communication between renderer and main processes
- API classes provide clean interfaces for IPC calls
- Handlers implement the actual logic in the main process
- Schemas define data contracts with Zod validation
- Electron main process code
- Handles window creation, app lifecycle, and system integration
- Registers IPC handlers and manages app state
- Security bridge between renderer and main processes
- Exposes safe APIs to the renderer process
- Implements context isolation for security
- UI Development: Work in
app/
directory with React components - IPC Communication: Define schemas, add API methods, implement handlers
- Window Features: Customize window behavior in
app/components/window/
- Prettier Formatting: Use
npm run format
to format the code. - ESLint: Use
npm run lint
to lint the code.
The project uses TypeScript path aliases for clean imports:
// Instead of relative paths like:
import { Button } from '../../../components/ui/button'
// Use clean aliases:
import { Button } from '@/app/components/ui/button'
import { conveyor } from '@/lib/conveyor/api'
Configured aliases by default, customise as you want:
@/
→app/
(application code - renderer process)@/lib/
→lib/
(shared library code containing conveyor, main, preload, etc.)@/resources/
→resources/
(build resources for the application)