--- title: Dialogs API description: Complete reference for native dialog APIs sidebar: order: 5 --- import { Card, CardGrid } from "@astrojs/starlight/components"; ## Overview The Dialogs API provides methods to show native file dialogs and message dialogs. Access dialogs through the `app.Dialog` manager. **Dialog Types:** - **File Dialogs** - Open and Save dialogs - **Message Dialogs** - Info, Error, Warning, and Question dialogs All dialogs are **native OS dialogs** that match the platform's look and feel. ## Accessing Dialogs Dialogs are accessed through the `app.Dialog` manager: ```go app.Dialog.OpenFile() app.Dialog.SaveFile() app.Dialog.Info() app.Dialog.Question() app.Dialog.Warning() app.Dialog.Error() ``` ## File Dialogs ### OpenFile() Creates a file open dialog. ```go func (dm *DialogManager) OpenFile() *OpenFileDialogStruct ``` **Example:** ```go dialog := app.Dialog.OpenFile() ``` ### OpenFileDialogStruct Methods #### SetTitle() Sets the dialog title. ```go func (d *OpenFileDialogStruct) SetTitle(title string) *OpenFileDialogStruct ``` **Example:** ```go dialog.SetTitle("Select Image") ``` #### AddFilter() Adds a file type filter. ```go func (d *OpenFileDialogStruct) AddFilter(displayName, pattern string) *OpenFileDialogStruct ``` **Parameters:** - `displayName` - Filter description shown to user (e.g., "Images", "Documents") - `pattern` - Semicolon-separated list of extensions (e.g., "*.png;*.jpg") **Example:** ```go dialog.AddFilter("Images", "*.png;*.jpg;*.gif"). AddFilter("Documents", "*.pdf;*.docx"). AddFilter("All Files", "*.*") ``` #### SetDirectory() Sets the initial directory. ```go func (d *OpenFileDialogStruct) SetDirectory(directory string) *OpenFileDialogStruct ``` **Example:** ```go homeDir, _ := os.UserHomeDir() dialog.SetDirectory(homeDir) ``` #### CanChooseDirectories() Enables or disables directory selection. ```go func (d *OpenFileDialogStruct) CanChooseDirectories(canChooseDirectories bool) *OpenFileDialogStruct ``` **Example (folder selection):** ```go // Select folders instead of files path, err := app.Dialog.OpenFile(). SetTitle("Select Folder"). CanChooseDirectories(true). CanChooseFiles(false). PromptForSingleSelection() ``` #### CanChooseFiles() Enables or disables file selection. ```go func (d *OpenFileDialogStruct) CanChooseFiles(canChooseFiles bool) *OpenFileDialogStruct ``` #### CanCreateDirectories() Enables or disables creating new directories. ```go func (d *OpenFileDialogStruct) CanCreateDirectories(canCreateDirectories bool) *OpenFileDialogStruct ``` #### ShowHiddenFiles() Shows or hides hidden files. ```go func (d *OpenFileDialogStruct) ShowHiddenFiles(showHiddenFiles bool) *OpenFileDialogStruct ``` #### AttachToWindow() Attaches the dialog to a specific window. ```go func (d *OpenFileDialogStruct) AttachToWindow(window Window) *OpenFileDialogStruct ``` #### PromptForSingleSelection() Shows the dialog and returns the selected file. ```go func (d *OpenFileDialogStruct) PromptForSingleSelection() (string, error) ``` **Returns:** - `string` - Selected file path (empty if cancelled) - `error` - Error if dialog failed **Example:** ```go path, err := app.Dialog.OpenFile(). SetTitle("Select Image"). AddFilter("Images", "*.png;*.jpg;*.gif"). PromptForSingleSelection() if err != nil { // User cancelled or error occurred return } // Use the selected file processFile(path) ``` #### PromptForMultipleSelection() Shows the dialog and returns multiple selected files. ```go func (d *OpenFileDialogStruct) PromptForMultipleSelection() ([]string, error) ``` **Returns:** - `[]string` - Array of selected file paths - `error` - Error if dialog failed **Example:** ```go paths, err := app.Dialog.OpenFile(). SetTitle("Select Images"). AddFilter("Images", "*.png;*.jpg"). PromptForMultipleSelection() if err != nil { return } for _, path := range paths { processFile(path) } ``` ### SaveFile() Creates a file save dialog. ```go func (dm *DialogManager) SaveFile() *SaveFileDialogStruct ``` **Example:** ```go dialog := app.Dialog.SaveFile() ``` ### SaveFileDialogStruct Methods #### SetTitle() Sets the dialog title. ```go func (d *SaveFileDialogStruct) SetTitle(title string) *SaveFileDialogStruct ``` #### SetFilename() Sets the default filename. ```go func (d *SaveFileDialogStruct) SetFilename(filename string) *SaveFileDialogStruct ``` **Example:** ```go dialog.SetFilename("document.pdf") ``` #### AddFilter() Adds a file type filter. ```go func (d *SaveFileDialogStruct) AddFilter(displayName, pattern string) *SaveFileDialogStruct ``` **Example:** ```go dialog.AddFilter("PDF Document", "*.pdf"). AddFilter("Text Document", "*.txt") ``` #### SetDirectory() Sets the initial directory. ```go func (d *SaveFileDialogStruct) SetDirectory(directory string) *SaveFileDialogStruct ``` #### AttachToWindow() Attaches the dialog to a specific window. ```go func (d *SaveFileDialogStruct) AttachToWindow(window Window) *SaveFileDialogStruct ``` #### PromptForSingleSelection() Shows the dialog and returns the save path. ```go func (d *SaveFileDialogStruct) PromptForSingleSelection() (string, error) ``` **Example:** ```go path, err := app.Dialog.SaveFile(). SetTitle("Save Document"). SetFilename("untitled.pdf"). AddFilter("PDF Document", "*.pdf"). PromptForSingleSelection() if err != nil { // User cancelled return } // Save to the selected path saveDocument(path) ``` ### Folder Selection There is no separate `SelectFolderDialog`. Use `OpenFile()` with directory options: ```go path, err := app.Dialog.OpenFile(). SetTitle("Select Output Folder"). CanChooseDirectories(true). CanChooseFiles(false). PromptForSingleSelection() if err != nil { // User cancelled return } // Use the selected folder outputDir = path ``` ## Message Dialogs All message dialogs return `*MessageDialog` and share the same methods. ### Info() Creates an information dialog. ```go func (dm *DialogManager) Info() *MessageDialog ``` **Example:** ```go app.Dialog.Info(). SetTitle("Success"). SetMessage("File saved successfully!"). Show() ``` ### Error() Creates an error dialog. ```go func (dm *DialogManager) Error() *MessageDialog ``` **Example:** ```go app.Dialog.Error(). SetTitle("Error"). SetMessage("Failed to save file: " + err.Error()). Show() ``` ### Warning() Creates a warning dialog. ```go func (dm *DialogManager) Warning() *MessageDialog ``` **Example:** ```go app.Dialog.Warning(). SetTitle("Warning"). SetMessage("This action cannot be undone."). Show() ``` ### Question() Creates a question dialog with custom buttons. ```go func (dm *DialogManager) Question() *MessageDialog ``` **Example:** ```go dialog := app.Dialog.Question(). SetTitle("Confirm"). SetMessage("Do you want to save changes?") save := dialog.AddButton("Save") save.OnClick(func() { saveDocument() }) dontSave := dialog.AddButton("Don't Save") dontSave.OnClick(func() { // Continue without saving }) cancel := dialog.AddButton("Cancel") cancel.OnClick(func() { // Do nothing }) dialog.SetDefaultButton(save) dialog.SetCancelButton(cancel) dialog.Show() ``` ### MessageDialog Methods #### SetTitle() Sets the dialog title. ```go func (d *MessageDialog) SetTitle(title string) *MessageDialog ``` #### SetMessage() Sets the dialog message. ```go func (d *MessageDialog) SetMessage(message string) *MessageDialog ``` #### SetIcon() Sets a custom icon for the dialog. ```go func (d *MessageDialog) SetIcon(icon []byte) *MessageDialog ``` #### AddButton() Adds a button to the dialog and returns the button for configuration. ```go func (d *MessageDialog) AddButton(label string) *Button ``` **Returns:** `*Button` - The button instance for further configuration **Example:** ```go button := dialog.AddButton("OK") button.OnClick(func() { // Handle click }) ``` #### SetDefaultButton() Sets which button is the default (activated by pressing Enter). ```go func (d *MessageDialog) SetDefaultButton(button *Button) *MessageDialog ``` **Example:** ```go yes := dialog.AddButton("Yes") no := dialog.AddButton("No") dialog.SetDefaultButton(yes) ``` #### SetCancelButton() Sets which button is the cancel button (activated by pressing Escape). ```go func (d *MessageDialog) SetCancelButton(button *Button) *MessageDialog ``` **Example:** ```go ok := dialog.AddButton("OK") cancel := dialog.AddButton("Cancel") dialog.SetCancelButton(cancel) ``` #### AttachToWindow() Attaches the dialog to a specific window. ```go func (d *MessageDialog) AttachToWindow(window Window) *MessageDialog ``` #### Show() Shows the dialog. Button callbacks handle user responses. ```go func (d *MessageDialog) Show() ``` **Note:** `Show()` does not return a value. Use button callbacks to handle user responses. ### Button Methods #### OnClick() Sets the callback function for when the button is clicked. ```go func (b *Button) OnClick(callback func()) *Button ``` #### SetAsDefault() Marks this button as the default button. ```go func (b *Button) SetAsDefault() *Button ``` #### SetAsCancel() Marks this button as the cancel button. ```go func (b *Button) SetAsCancel() *Button ``` ## Complete Examples ### File Selection Example ```go type FileService struct { app *application.App } func (s *FileService) OpenImage() (string, error) { path, err := s.app.Dialog.OpenFile(). SetTitle("Select Image"). AddFilter("Images", "*.png;*.jpg;*.jpeg;*.gif"). AddFilter("All Files", "*.*"). PromptForSingleSelection() if err != nil { return "", err } return path, nil } func (s *FileService) SaveDocument(defaultName string) (string, error) { path, err := s.app.Dialog.SaveFile(). SetTitle("Save Document"). SetFilename(defaultName). AddFilter("PDF Document", "*.pdf"). AddFilter("Text Document", "*.txt"). PromptForSingleSelection() if err != nil { return "", err } return path, nil } func (s *FileService) SelectOutputFolder() (string, error) { path, err := s.app.Dialog.OpenFile(). SetTitle("Select Output Folder"). CanChooseDirectories(true). CanChooseFiles(false). PromptForSingleSelection() if err != nil { return "", err } return path, nil } ``` ### Confirmation Dialog Example ```go func (s *Service) DeleteItem(app *application.App, id string) { dialog := app.Dialog.Question(). SetTitle("Confirm Delete"). SetMessage("Are you sure you want to delete this item?") deleteBtn := dialog.AddButton("Delete") deleteBtn.OnClick(func() { deleteFromDatabase(id) }) cancelBtn := dialog.AddButton("Cancel") // Cancel does nothing dialog.SetDefaultButton(cancelBtn) // Default to Cancel for safety dialog.SetCancelButton(cancelBtn) dialog.Show() } ``` ### Save Changes Dialog ```go func (s *Editor) PromptSaveChanges(app *application.App) { dialog := app.Dialog.Question(). SetTitle("Unsaved Changes"). SetMessage("Do you want to save your changes before closing?") save := dialog.AddButton("Save") save.OnClick(func() { s.Save() s.Close() }) dontSave := dialog.AddButton("Don't Save") dontSave.OnClick(func() { s.Close() }) cancel := dialog.AddButton("Cancel") // Cancel does nothing, dialog closes dialog.SetDefaultButton(save) dialog.SetCancelButton(cancel) dialog.Show() } ``` ### Multi-File Processing ```go func (s *Service) ProcessMultipleFiles(app *application.App) error { // Select multiple files paths, err := app.Dialog.OpenFile(). SetTitle("Select Files to Process"). AddFilter("Images", "*.png;*.jpg"). PromptForMultipleSelection() if err != nil { return err } if len(paths) == 0 { app.Dialog.Info(). SetTitle("No Files Selected"). SetMessage("Please select at least one file."). Show() return nil } // Process files for _, path := range paths { err := processFile(path) if err != nil { app.Dialog.Error(). SetTitle("Processing Error"). SetMessage(fmt.Sprintf("Failed to process %s: %v", path, err)). Show() continue } } // Show completion app.Dialog.Info(). SetTitle("Complete"). SetMessage(fmt.Sprintf("Successfully processed %d files", len(paths))). Show() return nil } ``` ### Error Handling with Dialogs ```go func (s *Service) SaveFile(app *application.App, data []byte) error { // Select save location path, err := app.Dialog.SaveFile(). SetTitle("Save File"). SetFilename("data.json"). AddFilter("JSON File", "*.json"). PromptForSingleSelection() if err != nil { // User cancelled - not an error return nil } // Attempt to save err = os.WriteFile(path, data, 0644) if err != nil { // Show error dialog app.Dialog.Error(). SetTitle("Save Failed"). SetMessage(fmt.Sprintf("Could not save file: %v", err)). Show() return err } // Show success app.Dialog.Info(). SetTitle("Success"). SetMessage("File saved successfully!"). Show() return nil } ``` ### Platform-Specific Defaults ```go import ( "os" "path/filepath" "runtime" ) func (s *Service) GetDefaultDirectory() string { homeDir, _ := os.UserHomeDir() switch runtime.GOOS { case "windows": return filepath.Join(homeDir, "Documents") case "darwin": return filepath.Join(homeDir, "Documents") case "linux": return filepath.Join(homeDir, "Documents") default: return homeDir } } func (s *Service) OpenWithDefaults(app *application.App) (string, error) { return app.Dialog.OpenFile(). SetTitle("Open File"). SetDirectory(s.GetDefaultDirectory()). AddFilter("All Files", "*.*"). PromptForSingleSelection() } ``` ## Best Practices ### Do - **Use native dialogs** - They match the platform's look and feel - **Provide clear titles** - Help users understand the purpose - **Set appropriate filters** - Guide users to correct file types - **Handle cancellation** - Check for errors (user may cancel) - **Show confirmation for destructive actions** - Use Question dialogs - **Provide feedback** - Use Info dialogs for success messages - **Set sensible defaults** - Default directory, filename, etc. - **Use callbacks for button actions** - Handle user responses properly ### Don't - **Don't ignore errors** - User cancellation returns an error - **Don't use ambiguous button labels** - Be specific: "Save"/"Cancel" - **Don't overuse dialogs** - They interrupt workflow - **Don't show errors for cancellation** - It's a normal action - **Don't forget file filters** - Help users find the right files - **Don't hardcode paths** - Use os.UserHomeDir() or similar ## Dialog Types by Platform ### macOS - Dialogs slide down from title bar - "Sheet" style attached to parent window - Native macOS appearance ### Windows - Standard Windows dialogs - Follows Windows design guidelines - Modern Windows 10/11 appearance ### Linux - GTK dialogs on GTK-based systems - Qt dialogs on Qt-based systems - Matches desktop environment #### Linux GTK4 Limitations On Linux with GTK4 (the default for modern distributions), file dialogs use the **xdg-desktop-portal** for native integration. This provides better desktop integration but means some options have no effect: | Option | GTK3 | GTK4 | Notes | |--------|------|------|-------| | `ShowHiddenFiles()` | ✅ Works | ❌ No effect | User controls via dialog's UI toggle (Ctrl+H or menu) | | `CanCreateDirectories()` | ✅ Works | ❌ No effect | Always enabled in the portal | | `ResolvesAliases()` | ✅ Works | ❌ No effect | Portal handles symlink resolution | | `SetButtonText()` | ✅ Works | ✅ Works | Custom accept button text works | **Why these limitations exist:** GTK4's portal-based dialogs delegate UI control to the desktop environment (GNOME, KDE, etc.). This is by design - the portal provides consistent UX across applications and respects user preferences. :::note The table above shows GTK4 behavior when building with `-tags gtk4`. By default, Wails uses GTK3 which provides full control over these dialog options. ::: ## Common Patterns ### "Save As" Pattern ```go func (s *Service) SaveAs(app *application.App, currentPath string) (string, error) { // Extract filename from current path filename := filepath.Base(currentPath) // Show save dialog path, err := app.Dialog.SaveFile(). SetTitle("Save As"). SetFilename(filename). PromptForSingleSelection() if err != nil { return "", err } return path, nil } ``` ### "Open Recent" Pattern ```go func (s *Service) OpenRecent(app *application.App, recentPath string) error { // Check if file still exists if _, err := os.Stat(recentPath); os.IsNotExist(err) { dialog := app.Dialog.Question(). SetTitle("File Not Found"). SetMessage("The file no longer exists. Remove from recent files?") remove := dialog.AddButton("Remove") remove.OnClick(func() { s.removeFromRecent(recentPath) }) cancel := dialog.AddButton("Cancel") dialog.SetCancelButton(cancel) dialog.Show() return err } return s.openFile(recentPath) } ```