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. [Link]
🔹 React - The library for web and native user interfaces. [Link]
🔹 TypeScript - Type-safe JavaScript. [Link]
🔹 Shadcn UI - Beautiful and accessible component library. [Link]
🔹 TailwindCSS - Utility-first CSS framework. [Link]
🔹 Electron Vite - Lightning-fast build tool based on Vite for fastest hot-reload. [Link]
🔹 Electron Builder - Configured for packaging applications. [Link]
Feature | Description |
---|---|
Conveyor | Type-safe inter-process communication with Zod validation |
Custom Titlebar & Menus | Style the window titlebar and menus as you want |
Clean Project Structure | Separation of main and renderer processes |
Resources Protocol | Access local file resources 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.
Conveyor is a type-safe IPC system that enables secure communication between your React frontend and Electron's main process. It uses Zod schemas for runtime validation and provides full TypeScript support.
🔹 Type-safe - Full TypeScript support with compile-time and runtime validation
🔹 Secure - Validates all data using Zod schemas
🔹 Modular - Clean API structure with organized handlers
🔹 Simple - Easy-to-use React hooks and global APIs
Use the useConveyor
hook in your React components:
import { useConveyor } from '@/app/hooks/use-conveyor'
function MyComponent() {
const { version } = useConveyor('app')
const { windowMinimize } = useConveyor('window')
const handleGetVersion = async () => {
console.log('App version:', await version())
console.log('App version:', await window.conveyor.app.version()) // OR
}
return (
<div>
<button onClick={handleGetVersion}>Get Version</button>
<button onClick={windowMinimize}>Minimize Window</button>
</div>
)
}
Conveyor provides two ways to access IPC methods:
// Method 1: React Hook (Recommended)
const { version } = useConveyor('app')
await version()
// Method 2: React Hook Global Conveyor
const conveyor = useConveyor()
await conveyor.app.version()
// Method 3: Global Window Object
await window.conveyor.app.version()
API | Description | Example |
---|---|---|
app |
App specfiic operations | conveyor.app.version() |
window |
Window specific operations | conveyor.window.windowMinimize() |
Follow these 4 simple steps to add your own IPC methods:
Create a schema in lib/conveyor/schemas/app-schema.ts
:
import { z } from 'zod'
export const appIpcSchema = {
// Simple method with no parameters
'get-app-info': {
args: z.tuple([]),
return: z.object({
name: z.string(),
version: z.string(),
platform: z.string(),
}),
},
// Method with parameters
'save-user-preference': {
args: z.tuple([
z.object({
key: z.string(),
value: z.string(),
}),
]),
return: z.boolean(),
},
} as const
Update lib/conveyor/api/app-api.ts
:
export class AppApi extends ConveyorApi {
getAppInfo = () => this.invoke('get-app-info')
saveUserPreference = (key: string, value: string) => this.invoke('save-user-preference', { key, value })
}
Add handler in lib/conveyor/handlers/app-handler.ts
:
import { handle } from '@/lib/main/shared'
import { app } from 'electron'
export const registerAppHandlers = () => {
handle('get-app-info', () => ({
name: app.getName(),
version: app.getVersion(),
platform: process.platform,
}))
handle('save-user-preference', async ({ key, value }) => {
// Save to file, database, etc.
console.log(`Saving ${key}: ${value}`)
return true
})
}
In lib/main/app.ts
:
import { registerAppHandlers } from '@/lib/conveyor/handlers/app-handler'
// During app initialization
registerAppHandlers()
function SettingsComponent() {
const conveyor = useConveyor()
const [appInfo, setAppInfo] = useState(null)
useEffect(() => {
// Get app information
conveyor.app.getAppInfo().then(setAppInfo)
}, [])
const saveTheme = (theme: string) => {
conveyor.app.saveUserPreference('theme', theme)
}
return (
<div>
<h2>App Info</h2>
{appInfo && (
<p>
{appInfo.name} v{appInfo.version} on {appInfo.platform}
</p>
)}
<button onClick={() => saveTheme('dark')}>Set Dark Theme</button>
</div>
)
}
const handleApiCall = async () => {
try {
const result = await conveyor.app.getAppInfo()
console.log('Success:', result)
} catch (error) {
console.error('API call failed:', error)
// Handle validation errors, network issues, etc.
}
}
// ✅ TypeScript enforces correct types
const info = await conveyor.app.getAppInfo() // Returns { name: string, version: string, platform: string }
// ❌ TypeScript error - wrong parameter type
const result = await conveyor.app.saveUserPreference(123, 'value') // Error: Expected string, got number
// ✅ Runtime validation ensures data integrity
const valid = await conveyor.app.saveUserPreference('theme', 'dark') // Validates at runtime
📖 For advanced usage and detailed documentation, see Conveyor README
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)
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.