--- title: Message dialogs description: Display information, warnings, errors, and questions sidebar: order: 2 --- import { Card, CardGrid } from "@astrojs/starlight/components"; ## Message dialogs Wails provides **native message dialogs** with platform-appropriate appearance: info, warning, error, and question dialogs with customisable titles, messages, and buttons. Simple API, native behaviour, accessible by default. ## Creating Dialogs Message dialogs are accessed through the `app.Dialog` manager: ```go app.Dialog.Info() app.Dialog.Question() app.Dialog.Warning() app.Dialog.Error() ``` All methods return a `*MessageDialog` that can be configured using method chaining. ## Information dialog Display informational messages: ```go app.Dialog.Info(). SetTitle("Success"). SetMessage("File saved successfully!"). Show() ``` **Use cases:** - Success confirmations - Completion notices - Informational messages - Status updates **Example - Save confirmation:** ```go func saveFile(app *application.App, path string, data []byte) error { if err := os.WriteFile(path, data, 0644); err != nil { return err } app.Dialog.Info(). SetTitle("File Saved"). SetMessage(fmt.Sprintf("Saved to %s", filepath.Base(path))). Show() return nil } ``` ## Warning dialog Show warnings: ```go app.Dialog.Warning(). SetTitle("Warning"). SetMessage("This action cannot be undone."). Show() ``` **Use cases:** - Non-critical warnings - Deprecation notices - Caution messages - Potential issues **Example - Disk space warning:** ```go func checkDiskSpace(app *application.App) { available := getDiskSpace() if available < 100*1024*1024 { // Less than 100MB app.Dialog.Warning(). SetTitle("Low Disk Space"). SetMessage(fmt.Sprintf("Only %d MB available.", available/(1024*1024))). Show() } } ``` ## Error dialog Display errors: ```go app.Dialog.Error(). SetTitle("Error"). SetMessage("Failed to connect to server."). Show() ``` **Use cases:** - Error messages - Failure notifications - Exception handling - Critical issues **Example - Network error:** ```go func fetchData(app *application.App, url string) ([]byte, error) { resp, err := http.Get(url) if err != nil { app.Dialog.Error(). SetTitle("Network Error"). SetMessage(fmt.Sprintf("Failed to connect: %v", err)). Show() return nil, err } defer resp.Body.Close() return io.ReadAll(resp.Body) } ``` ## Question dialog Ask users questions and handle responses via button callbacks: ```go dialog := app.Dialog.Question(). SetTitle("Confirm"). SetMessage("Save changes before closing?") save := dialog.AddButton("Save") save.OnClick(func() { saveChanges() }) dontSave := dialog.AddButton("Don't Save") dontSave.OnClick(func() { // Continue without saving }) cancel := dialog.AddButton("Cancel") cancel.OnClick(func() { // Don't close }) dialog.SetDefaultButton(save) dialog.SetCancelButton(cancel) dialog.Show() ``` **Use cases:** - Confirm actions - Yes/No questions - Multiple choice - User decisions **Example - Unsaved changes:** ```go func closeDocument(app *application.App) { if !hasUnsavedChanges() { doClose() return } dialog := app.Dialog.Question(). SetTitle("Unsaved Changes"). SetMessage("Do you want to save your changes?") save := dialog.AddButton("Save") save.OnClick(func() { if saveDocument() { doClose() } }) dontSave := dialog.AddButton("Don't Save") dontSave.OnClick(func() { doClose() }) cancel := dialog.AddButton("Cancel") // Cancel button has no callback - just closes the dialog dialog.SetDefaultButton(save) dialog.SetCancelButton(cancel) dialog.Show() } ``` ## dialog Options ### Title and Message ```go dialog := app.Dialog.Info(). SetTitle("Operation Complete"). SetMessage("All files have been processed successfully.") ``` **Best practices:** - **Title:** Short, descriptive (2-5 words) - **Message:** Clear, specific, actionable - **Avoid jargon:** Use plain language ### Buttons **Single button (Info/Warning/Error):** Info, warning, and error dialogs display a default "OK" button: ```go app.Dialog.Info(). SetMessage("Done!"). Show() ``` You can also add custom buttons: ```go dialog := app.Dialog.Info(). SetMessage("Done!") ok := dialog.AddButton("Got it!") dialog.SetDefaultButton(ok) dialog.Show() ``` **Multiple buttons (Question):** Use `AddButton()` to add buttons, which returns a `*Button` you can configure: ```go dialog := app.Dialog.Question(). SetMessage("Choose an action") option1 := dialog.AddButton("Option 1") option1.OnClick(func() { handleOption1() }) option2 := dialog.AddButton("Option 2") option2.OnClick(func() { handleOption2() }) option3 := dialog.AddButton("Option 3") option3.OnClick(func() { handleOption3() }) dialog.Show() ``` **Default and Cancel buttons:** Use `SetDefaultButton()` to specify which button is highlighted and triggered by Enter. Use `SetCancelButton()` to specify which button is triggered by Escape. ```go dialog := app.Dialog.Question(). SetMessage("Delete file?") deleteBtn := dialog.AddButton("Delete") deleteBtn.OnClick(func() { performDelete() }) cancelBtn := dialog.AddButton("Cancel") // No callback needed - just dismisses dialog dialog.SetDefaultButton(cancelBtn) // Safe option as default dialog.SetCancelButton(cancelBtn) // Escape triggers Cancel dialog.Show() ``` You can also use the fluent `SetAsDefault()` and `SetAsCancel()` methods on buttons: ```go dialog := app.Dialog.Question(). SetMessage("Delete file?") dialog.AddButton("Delete").OnClick(func() { performDelete() }) dialog.AddButton("Cancel").SetAsDefault().SetAsCancel() dialog.Show() ``` **Best practices:** - **1-3 buttons:** Don't overwhelm users - **Clear labels:** "Save" not "OK" - **Safe default:** Non-destructive action - **Order matters:** Most likely action first (except Cancel) ### Custom Icon Set a custom icon for the dialog: ```go app.Dialog.Info(). SetTitle("Custom Icon Example"). SetMessage("Using a custom icon"). SetIcon(myIconBytes). Show() ``` ### Window Attachment Attach to specific window: ```go dialog := app.Dialog.Question(). SetMessage("Window-specific question"). AttachToWindow(window) dialog.AddButton("OK") dialog.Show() ``` **Benefits:** - dialog appears on correct window - Parent window disabled whilst shown - Better multi-window UX ## Complete Examples ### Confirm Destructive Action ```go func deleteFiles(app *application.App, paths []string) { // Confirm deletion message := fmt.Sprintf("Delete %d file(s)?", len(paths)) if len(paths) == 1 { message = fmt.Sprintf("Delete %s?", filepath.Base(paths[0])) } dialog := app.Dialog.Question(). SetTitle("Confirm Delete"). SetMessage(message) deleteBtn := dialog.AddButton("Delete") deleteBtn.OnClick(func() { // Perform deletion var errs []error for _, path := range paths { if err := os.Remove(path); err != nil { errs = append(errs, err) } } // Show result if len(errs) > 0 { app.Dialog.Error(). SetTitle("Delete Failed"). SetMessage(fmt.Sprintf("Failed to delete %d file(s)", len(errs))). Show() } else { app.Dialog.Info(). SetTitle("Delete Complete"). SetMessage(fmt.Sprintf("Deleted %d file(s)", len(paths))). Show() } }) cancelBtn := dialog.AddButton("Cancel") dialog.SetDefaultButton(cancelBtn) dialog.SetCancelButton(cancelBtn) dialog.Show() } ``` ### Quit Confirmation ```go func confirmQuit(app *application.App) { dialog := app.Dialog.Question(). SetTitle("Quit"). SetMessage("You have unsaved work. Are you sure you want to quit?") yes := dialog.AddButton("Yes") yes.OnClick(func() { app.Quit() }) no := dialog.AddButton("No") dialog.SetDefaultButton(no) dialog.Show() } ``` ### Update Dialog with Download Option ```go func showUpdateDialog(app *application.App) { dialog := app.Dialog.Question(). SetTitle("Update"). SetMessage("A new version is available. The cancel button is selected when pressing escape.") download := dialog.AddButton("📥 Download") download.OnClick(func() { app.Dialog.Info().SetMessage("Downloading...").Show() }) cancel := dialog.AddButton("Cancel") dialog.SetDefaultButton(download) dialog.SetCancelButton(cancel) dialog.Show() } ``` ### Custom Icon Question ```go func showCustomIconQuestion(app *application.App, iconBytes []byte) { dialog := app.Dialog.Question(). SetTitle("Custom Icon Example"). SetMessage("Using a custom icon"). SetIcon(iconBytes) likeIt := dialog.AddButton("I like it!") likeIt.OnClick(func() { app.Dialog.Info().SetMessage("Thanks!").Show() }) notKeen := dialog.AddButton("Not so keen...") notKeen.OnClick(func() { app.Dialog.Info().SetMessage("Too bad!").Show() }) dialog.SetDefaultButton(likeIt) dialog.Show() } ## Best Practices ### ✅ Do - **Be specific** - "File saved to Documents" not "Success" - **Use appropriate type** - Error for errors, Warning for warnings - **Provide context** - Include relevant details - **Use clear button labels** - "Delete" not "OK" - **Set safe defaults** - Non-destructive action - **Handle cancellation** - User might close dialog ### ❌ Don't - **Don't overuse** - Interrupts workflow - **Don't use for frequent updates** - Use notifications instead - **Don't use generic messages** - "Error" tells nothing - **Don't ignore errors** - Handle dialog.Show() errors - **Don't block unnecessarily** - Consider async alternatives - **Don't use technical jargon** - Plain language ## Platform Differences ### macOS - Sheet-style when attached to window - Standard keyboard shortcuts (⌘. for Cancel) - Follows system theme automatically - Accessibility built-in ### Windows - Modal dialogs - TaskDialog appearance - Esc for Cancel - Follows system theme ### Linux - GTK dialogs - Varies by desktop environment - Follows desktop theme - Standard keyboard navigation ## Next Steps Open, save, and folder selection. [Learn More →](/features/dialogs/file) Create custom dialog windows. [Learn More →](/features/dialogs/custom) Non-intrusive notifications. [Learn More →](/features/notifications) Use events for non-blocking communication. [Learn More →](/features/events/system) --- **Questions?** Ask in [Discord](https://discord.gg/JDdSxwjhGf) or check the [dialog examples](https://github.com/wailsapp/wails/tree/v3-alpha/v3/examples/dialogs).