516 lines
11 KiB
Text
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).
|