Native Datei-Dialoge und Message-Boxen sind Standard-Aufgaben jeder Desktop-App. Electrons dialog-Modul liefert plattform-konforme Dialoge mit minimaler API — von einfacher Bestätigung bis zu Multi-Datei-Auswahl mit Filter.
Datei öffnen — showOpenDialog
import { dialog } from 'electron';
const result = await dialog.showOpenDialog(mainWindow, {
title: 'Datei öffnen',
defaultPath: app.getPath('documents'),
buttonLabel: 'Öffnen',
filters: [
{ name: 'Bilder', extensions: ['jpg', 'png', 'gif'] },
{ name: 'Alle Dateien', extensions: ['*'] }
],
properties: ['openFile'] // 'openDirectory', 'multiSelections', 'showHiddenFiles'
});
if (!result.canceled) {
console.log('Ausgewählt:', result.filePaths[0]);
}properties:
openFile— Datei-AuswahlopenDirectory— Verzeichnis-AuswahlmultiSelections— Mehrfach-Auswahl erlaubenshowHiddenFiles— versteckte Dateien zeigencreateDirectory(macOS) — User darf neuen Ordner anlegen
Datei speichern — showSaveDialog
const result = await dialog.showSaveDialog(mainWindow, {
title: 'Speichern',
defaultPath: 'untitled.json',
filters: [
{ name: 'JSON', extensions: ['json'] }
]
});
if (!result.canceled) {
await fs.writeFile(result.filePath, jsonContent);
}defaultPath kann sowohl ein absoluter Pfad als auch nur ein Dateiname sein — bei Letzterem öffnet sich der Dialog im letzten verwendeten Verzeichnis.
Message-Boxen
const result = await dialog.showMessageBox(mainWindow, {
type: 'question', // 'none', 'info', 'error', 'question', 'warning'
title: 'Datei löschen?',
message: 'Wirklich löschen?',
detail: 'Die Datei wird unwiderruflich entfernt.',
buttons: ['Löschen', 'Abbrechen'],
defaultId: 1, // Default-Button
cancelId: 1 // Welcher Button = ESC
});
if (result.response === 0) {
await deleteFile();
}response ist der Index des geklickten Buttons. cancelId macht ESC zu einem expliziten „Abbrechen".
Error-Box
// Synchron, ohne Window-Referenz
dialog.showErrorBox('Fehler', 'Datei konnte nicht geöffnet werden.');Sehr simpel — ein Title, eine Message. Praktisch für unerwartete Fehler beim App-Start, bevor Fenster verfügbar sind.
Modal vs. Modeless
Mit Window-Referenz (mainWindow als erstes Argument): modal — der Dialog blockt das Fenster, andere Fenster bleiben benutzbar.
Ohne Window-Referenz: App-modal auf macOS (App komplett blockiert), modeless auf Windows.
// Modal zum Hauptfenster — empfohlen
await dialog.showOpenDialog(mainWindow, options);
// App-modal — blockt alles auf macOS
await dialog.showOpenDialog(options);File-Filter — Format und Reihenfolge
filters: [
{ name: 'Bilder', extensions: ['jpg', 'jpeg', 'png', 'gif'] },
{ name: 'Dokumente', extensions: ['pdf', 'docx'] },
{ name: 'Alle', extensions: ['*'] }
]Erste Filter ist Default-aktiv. User kann via Dropdown wechseln. * matched alles — sinnvoll als letzter Eintrag.
Cross-Platform-Eigenheit: macOS zeigt Filter weniger prominent als Windows. Auf macOS sind Filter eher „Hint", auf Windows sind sie strikter.
Aus dem Renderer aufrufen
Dialog-API ist Main-only. Renderer ruft via IPC:
ipcMain.handle('dialog:open-file', async () => {
const result = await dialog.showOpenDialog(mainWindow, {
properties: ['openFile']
});
return result.canceled ? null : result.filePaths[0];
});contextBridge.exposeInMainWorld('api', {
openFile: () => ipcRenderer.invoke('dialog:open-file')
});const path = await window.api.openFile();
if (path) {
// Datei lesen via separater IPC-Methode
}Interessantes
Window-Referenz übergeben — sonst ungewollt App-modal.
Dialog ohne erstes Argument blockt auf macOS die ganze App. Mit dialog.showOpenDialog(mainWindow, ...) wird er sauber an das Fenster gebunden — andere Fenster bleiben aktiv.
showOpenDialog ist async, ältere Variante hatte Callback.
Modern: Promise-based mit await. In alten Beispielen siehst du noch den Callback-Stil — geht weiter, ist aber abgekündigt. Immer auf Promise umstellen.
filePaths ist Array, auch bei Single-Select.
Pattern: result.filePaths[0] für Single-Select. Bei multiSelections: true ist das ganze Array relevant.
defaultPath für besseren UX.
Default-Pfad sollte zum Kontext passen — beim „Bild öffnen" der pictures-Pfad, beim Speichern der zuletzt verwendete Ordner. Userdaten merken (electron-store) und beim nächsten Mal vorbelegen.
cancelId separat zur Button-Reihenfolge.
Bei „Löschen / Abbrechen" mit Buttons [Löschen, Abbrechen]: cancelId: 1 (ESC = Abbrechen). Ohne cancelId weiß Electron nicht, welcher Button ESC entspricht — kann auf manchen Plattformen Default-Button auswählen statt Abbrechen.
showErrorBox ist synchron — eine Ausnahme.
Anders als der Rest des Dialog-APIs ist showErrorBox sync. Praktisch für „App startet nicht, ich muss SOFORT was zeigen". Sonst eher showMessageBox mit type: 'error'.
Weiterführende Ressourcen
Externe Quellen
- dialog
- Native File Drag & Drop
- File API (MDN) — alternative Web-API für Datei-Auswahl