gui/docs/ref/wails-v3/features/dialogs/message.mdx
Snider 4bdbb68f46
Some checks failed
Security Scan / security (push) Failing after 9s
Test / test (push) Failing after 1m21s
refactor: update import path from go-config to core/config
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-14 10:26:36 +00:00

516 lines
11 KiB
Text

---
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
<CardGrid>
<Card title="File dialogs" icon="document">
Open, save, and folder selection.
[Learn More →](/features/dialogs/file)
</Card>
<Card title="Custom dialogs" icon="puzzle">
Create custom dialog windows.
[Learn More →](/features/dialogs/custom)
</Card>
<Card title="Notifications" icon="bell">
Non-intrusive notifications.
[Learn More →](/features/notifications)
</Card>
<Card title="Events" icon="star">
Use events for non-blocking communication.
[Learn More →](/features/events/system)
</Card>
</CardGrid>
---
**Questions?** Ask in [Discord](https://discord.gg/JDdSxwjhGf) or check the [dialog examples](https://github.com/wailsapp/wails/tree/v3-alpha/v3/examples/dialogs).