In Electron, the window is the core carrier for application-user interaction.
All visual interfaces run in the **Renderer Process**, while the creation and control of these windows are managed by the **Main Process**.
* * *
## Creating and Managing Windows
Electron creates windows through the `BrowserWindow` class.
In the main process, a new window is defined as follows:
## Example
const{ BrowserWindow }= require('electron')
let mainWindow =new BrowserWindow({
width:1200,
height:800,
show:false,// Wait for page to be ready before showing
webPreferences:{
preload: path.join(__dirname,'preload.js'),
},
})
**BrowserWindow Configuration Options**
* `width` / `height`: Window width and height.
* `minWidth` / `minHeight`: Minimum size limits.
* `resizable`: Whether resizing is allowed.
* `fullscreen` / `fullscreenable`: Whether to enable fullscreen.
* `frame`: Whether to display the native title bar (commonly disabled for custom title bars).
* `transparent`: Transparent window (can achieve frosted glass, floating effects, etc.).
* `alwaysOnTop`: Whether the window stays on top.
**Window Size, Position, and State**
Window states can be controlled through APIs:
mainWindow.maximize() // Maximize mainWindow.minimize() // Minimize mainWindow.restore() // Restore mainWindow.setBounds({ x: 100, y: 100, width: 800, height: 600 }) // Adjust position and size
You can also listen for window changes:
mainWindow.on('resize', () => console.log('Window size changed')) mainWindow.on('move', () => console.log('Window moved'))
**Borderless Window and Custom Title Bar**
After setting `frame: false`, you can customize the title bar area and simulate dragging through CSS and JS:
.titlebar { -webkit-app-region: drag;}
Note that non-draggable areas (such as buttons) should have:
.titlebar { -webkit-app-region: drag;}
**Window Event Listening**
mainWindow.on('close', (e) => { e.preventDefault() mainWindow.hide()})
Common events include:
* `ready-to-show`: Page loading complete, safe to display.
* `focus` / `blur`: Window gains or loses focus.
* `closed`: Window has been destroyed.
* * *
## Loading Page Content
Electron windows can load local HTML files or remote websites.
**Loading Local HTML Files**
mainWindow.loadFile('index.html')
**Loading Remote URLs**
mainWindow.loadURL('https://example.com')
**Using Frontend Frameworks**
If you use modern frameworks like Vue, React, or Angular, you can load the built static files into the window:
mainWindow.loadFile(path.join(__dirname, 'dist/index.html'))
Or load a local development server:
mainWindow.loadURL('http://localhost:5173')
* * *
## Inter-Window Communication
In multi-window applications, you may need to pass data or control behavior between windows.
**Parent-Child Window Relationship**
You can specify `parent` when creating a new window:
let child = new BrowserWindow({ parent: mainWindow, modal: true, // Modal window width: 400, height: 300,})
When the parent window closes, the child window will automatically close.
**Multi-Window Data Sharing**
Data can be passed between different renderer processes through the main process as an intermediary, or by using global objects or `ipcMain` / `ipcRenderer`.
**Window Message Passing**
The main process can directly operate the target window:
child.webContents.send('update-data', someData)
Receiving in the child window:
const { ipcRenderer } = require('electron') ipcRenderer.on('update-data', (event, data) => { console.log(data)})
* * *
## Interface Optimization
**Splash Screen**
When the main window loads slowly, you can first display a lightweight startup window:
const splash = new BrowserWindow({ width: 400, height: 300, frame: false }) splash.loadFile('splash.html') mainWindow.once('ready-to-show', () => { splash.close() mainWindow.show()})
**Window Display Optimization**
To prevent white screen flickering, common techniques include:
* Creating the window with `show: false`, then calling `show()` after loading completes.
* Setting background color in the rendered page.
* Preloading resources (icons, fonts, styles).
**Anti-Flickering Techniques**
* Enable GPU acceleration or disable hardware acceleration (depending on specific circumstances).
* Avoid complex animations or gradients in CSS.
* Use double-buffered rendering to reduce drawing jitter.
* * *
## Multi-Window Electron Application (with Splash Screen, Main Interface, and Child Window)
**Directory Structure**
my-electron-app/βββ package.json βββ main.js # Main process entryβββ preload.js # Preload scriptβββ splash.html # Splash screenβββ index.html # Main window pageβββ child.html # Child window pageβββ renderer.js # Renderer process logic
**main.js (Main Process)**
## Example
const{ app, BrowserWindow, ipcMain }= require('electron')
const path = require('path')
let mainWindow, splash, childWindow
function createSplash(){
splash =new BrowserWindow({
width:400,
height:300,
frame:false,
transparent:true,
alwaysOnTop:true,
})
splash.loadFile('splash.html')
}
function createMainWindow(){
mainWindow =new BrowserWindow({
width:1200,
height:800,
show:false,
webPreferences:{
preload: path.join(__dirname,'preload.js'),
},
})
mainWindow.loadFile('index.html')
// Show after page loading is complete
mainWindow.once('ready-to-show',()=>{
if(splash) splash.close()
mainWindow.show()
})
mainWindow.on('closed',()=>(mainWindow =null))
}
function createChildWindow(){
childWindow =new BrowserWindow({
parent: mainWindow,
modal:true,
width:400,
height:300,
webPreferences:{
preload: path.join(__dirname,'preload.js'),
},
})
childWindow.loadFile('child.html')
}
// Inter-process communication
ipcMain.on('open-child',()=>{
if(!childWindow) createChildWindow()
})
ipcMain.handle('get-app-info',()=>{
return{
name: app.getName(),
version: app.getVersion(),
}
})
app.on('ready',()=>{
createSplash()
setTimeout(()=> createMainWindow(),1500)
})
app.on('window-all-closed',()=>{
if(process.platform!=='darwin') app.quit()
})
preload.js (Preload Script)
const{ contextBridge, ipcRenderer }= require('electron')
contextBridge.exposeInMainWorld('electronAPI',{
openChild:()=> ipcRenderer.send('open-child'),
getAppInfo:()=> ipcRenderer.invoke('get-app-info'),
})
**index.html (Main Window)**
## Example
Main Window
Welcome to the Electron Application
**child.html (Child Window)**
## Example
Child Window
This is a child window
Can receive commands from the main window
**splash.html (Splash Screen)**
## Example
Loading...
Application starting, please wait...
**renderer.js (Renderer Logic)**
## Example
const info = document.getElementById('info')
const btn = document.getElementById('open')
// Display application information
window.electronAPI.getAppInfo().then((appInfo)=>{
info.textContent= `Application Name: ${appInfo.name} | Version: ${appInfo.version}`
})
// Open child window
btn.addEventListener('click',()=>{
window.electronAPI.openChild()
})
The runtime flow is as follows:
1. At startup, display the **splash screen** (`splash.html`).
2. After loading completes, automatically close the splash page and display the **main window**.
3. The main window can open the **child window** through a button, demonstrating IPC communication functionality.
4. The main window uses **Preload to securely expose APIs**, preventing direct access to Node.js.
5. All windows use **event listening**, **delayed display**, and other optimization strategies to avoid white screen and flickering.