Skip to content

guasam/electron-react-app

Repository files navigation

Electron React App

A modern Electron application template with React, Vite, TypeScript, and TailwindCSS. This project provides a solid foundation for developing cross-platform desktop applications.


Electron   React   TypeScript   Vite   Shadcn   Tailwind


Watch Video Preview


Stack

🔹 Electron - Cross-platform desktop application framework.
🔹 React - The library for web and native user interfaces.
🔹 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.


In-Built Features

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

Installation

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

Development

Start the development server:

npm run dev

This will start Electron with hot-reload enabled so you can see changes in real time.


Conveyor - Inter-Process Communication

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


Quick Start

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>
  )
}

Available APIs

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()

Built-in APIs

API Description Example
app App specfiic operations conveyor.app.version()
window Window specific operations conveyor.window.windowMinimize()

Creating Custom APIs

Follow these 4 simple steps to add your own IPC methods:

Step 1: Define Schema

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

Step 2: Add API Method

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 })
}

Step 3: Implement Handler

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
  })
}

Step 4: Register Handler

In lib/main/app.ts:

import { registerAppHandlers } from '@/lib/conveyor/handlers/app-handler'

// During app initialization
registerAppHandlers()

Usage in Components

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>
  )
}

Error Handling

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.
  }
}

Type Safety Benefits

// ✅ 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


Custom Window Components

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

Titlebar Menu Toggle

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

Customizing Menu Items

To add, remove or modify menu items, update the following file:

  • app/components/window/menus.ts

Tailwind CSS

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>
);

Key Directories Explained

app/ - Renderer Process

  • React application that runs in the browser window
  • Contains all UI components, styles, and client-side logic
  • Uses Vite for fast development and building

lib/conveyor/ - Conveyor - Inter-Process Communication

  • 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

lib/main/ - Main Process

  • Electron main process code
  • Handles window creation, app lifecycle, and system integration
  • Registers IPC handlers and manages app state

lib/preload/ - Preload Scripts

  • Security bridge between renderer and main processes
  • Exposes safe APIs to the renderer process
  • Implements context isolation for security

Development Workflow

  1. UI Development: Work in app/ directory with React components
  2. IPC Communication: Define schemas, add API methods, implement handlers
  3. Window Features: Customize window behavior in app/components/window/
  4. Prettier Formatting: Use npm run format to format the code.
  5. ESLint: Use npm run lint to lint the code.

Path Aliases

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)

Building for Production

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.

About

Modern Electron application starter kit with React, Vite, TypeScript, ShadcnUI and TailwindCSS.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 5