My goal is to explore Electron for cross-platform tools and utilize cursor.ai to bridge the learning curve gap since I’m most familiar with C++, C# and Python.
I began with a ChatGPT request for Electron + Typescript + Tailwind after tradeoff analysis. However, I ran into trouble with configuration issues leading me down a rabbit hole. During the process, I found Electron Forge (https://www.electronforge.io/) and decided to pivot.
Also note that when referring to “we” within this post, I’m indicating collaboration with Cursor AI chat. Since I am not very experienced in Typescript or Electron (I have enough practical web and typescript experience to be dangerous), I’m leaning on AI.
Part 1 - Hello World
Electron Forge provides a pleasant experience for initial projects, especially if web is not your main focus. Support from Stack Overflow or AI is sometimes difficult since Frameworks change more rapidly in the web space than elsewhere.
# create the project
npx create-electron-app@latest electron-forge-webpack-app --template=webpack-typescript
# build and run
cd electron-forge-webpack-app
npm start
Part 2 - Menu, About Box and Dashboard View
With the general structure in place, I wanted to demo basic views and menus.
Menus
I used Cursor AI composer to generate native Electron menus.
One thing to note is that the style looks different for these versus VSCode’s menus. I spent a little time looking for a way to alter the padding and radius that appears off, but no luck so far.
// Add this menu template before the createWindow function
const createMenu = (): void => {
const template: Electron.MenuItemConstructorOptions[] = [
{
label: 'File',
submenu: [
{
label: 'New Window',
accelerator: 'CmdOrCtrl+N',
click: () => createWindow(),
},
{ type: 'separator' },
{
label: 'Exit',
accelerator: process.platform === 'darwin' ? 'Cmd+Q' : 'Alt+F4',
click: () => app.quit(),
},
],
},
{
label: 'Edit',
submenu: [
{ label: 'Undo', accelerator: 'CmdOrCtrl+Z', role: 'undo' },
{ label: 'Redo', accelerator: 'Shift+CmdOrCtrl+Z', role: 'redo' },
{ type: 'separator' },
{ label: 'Cut', accelerator: 'CmdOrCtrl+X', role: 'cut' },
{ label: 'Copy', accelerator: 'CmdOrCtrl+C', role: 'copy' },
{ label: 'Paste', accelerator: 'CmdOrCtrl+V', role: 'paste' },
{ label: 'Select All', accelerator: 'CmdOrCtrl+A', role: 'selectAll' },
],
},
{
label: 'View',
submenu: [
{ role: 'reload' },
{ role: 'toggleDevTools' },
{ type: 'separator' },
{ role: 'resetZoom' },
{ role: 'zoomIn' },
{ role: 'zoomOut' },
{ type: 'separator' },
{ role: 'togglefullscreen' },
],
},
{
label: 'Help',
submenu: [
{
label: 'About',
click: async () => {
const parentWindow = BrowserWindow.getFocusedWindow();
const parentBounds = parentWindow.getBounds();
const aboutWindow = new BrowserWindow({
width: 300,
height: 500,
roundedCorners: false,
modal: true,
parent: parentWindow,
resizable: false,
minimizable: false,
maximizable: false,
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
});
// Calculate center position relative to parent window
const x = Math.round(parentBounds.x + (parentBounds.width - 300) / 2);
const y = Math.round(parentBounds.y + (parentBounds.height - 500) / 2);
aboutWindow.setPosition(x, y);
aboutWindow.setMenu(null);
aboutWindow.loadFile('src/views/about.html');
aboutWindow.once('ready-to-show', () => {
aboutWindow.show();
});
},
},
],
},
];
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
};
About Box
Originally, AI created a simple message box for the example; We iterated to build a more representative about box view.
Dashboard View
Next, I asked Cursor AI to generate a dashboard with the following prompt. It took some additional work and troubleshooting to install chart.js (e.g. npm install --save chart.js @types/chart.js
) since Cursor didn’t appear to have permissions to run this directly.
create a dashboard view which includes 4 primary monitors and a line chart of those primary monitors with a 30 second fifo window.
Scroll Issues
I ran into some trouble with scrollbars and took a while to sort out. The thing that ended up helping was this prompt. From the feedback of colors, we were able to correct a few issues, finally turning off the custom background colors once resolved.
Part 3 - Tailwind CSS, Toolbars and Status bar.
Next, I wanted to add standard toolbar and status bars, but kept running into layout problems. It seems that VSCode uses their own custom components, but AI suggested Tailwind as the best option.
Layout Struggles
I used a similar technique as earlier to color the elements to figure out the layout alignment issues. There does not appear to be standard toolbars or status bar elements in Electron. Unable to resolve this through some iteration, pivoted to using a UI framework.
Tailwind CSS
After applying Tailwind CSS and some additional iteration on window sizing, colors and layout, we have a traditional looking Windows application.
Part 4 - Multiple Views (stuck)
I’ve tried a few times with AI to adapt for multiple views (which seems like it should be a normal use case), but it cannot seem to find the proper page when I move files into the “views” folder… I’m not sure if this is a webpack config issue, but AI was doing random things that seemed off.
For now, I’m pivoting to try Tauri + React again. Please comment if there is a simple path forward; otherwise I may try a different combination when attempting Electron again.