home / skills / derklinke / codex-config / swiftui-macos-shortcuts

swiftui-macos-shortcuts skill

/skills/swiftui-macos-shortcuts

This skill helps you implement reliable macOS menu commands and keyboard shortcuts in SwiftUI by using FocusedValues and CommandGroup to ensure consistent Cmd

npx playbooks add skill derklinke/codex-config --skill swiftui-macos-shortcuts

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
2.0 KB
---
name: swiftui-macos-shortcuts
description: Use when implementing or debugging macOS menu commands and keyboard shortcuts in SwiftUI (Commands, CommandGroup, FocusedValues), especially for File menu Save/Reload or global app shortcuts.
---

# SwiftUI macOS Commands & Shortcuts

## Goal

Implement reliable menu items and keyboard shortcuts in SwiftUI macOS apps, including File menu actions that work across focused views.

## Quick guidance

- Prefer `Commands` + `CommandGroup` (declared on the `App` via `.commands { ... }`) for menu items. Add `.keyboardShortcut` to the `Button`.
- For actions that need app state, prefer `@FocusedValue` so commands resolve to the active window/view context.
- Provide a `FocusedValues` key with a small action struct (e.g., `FileMenuActions`) and set it on the root view via `.focusedValue(...)`.
- Avoid `@EnvironmentObject` inside `Commands` for core actions; it can fail to resolve if no view is focused or when the menu is built before env injection.
- Do not rely on toolbar buttons for keyboard shortcuts; attach shortcuts to menu items instead so Cmd+S/R consistently fire.

## Minimal pattern (File menu)

1) Define a focused value key:

- `struct FileMenuActions { var saveAll: () -> Void; var reloadAll: () -> Void }`
- `extension FocusedValues { var fileMenuActions: FileMenuActions? }`

2) Provide actions on the root view:

- `.focusedValue(\.fileMenuActions, FileMenuActions(saveAll: { ... }, reloadAll: { ... }))`

3) Add commands:

- `CommandGroup(after: .newItem) { Button("Save All") { fileMenuActions?.saveAll() }.keyboardShortcut("s") }`
- `Button("Reload All") { fileMenuActions?.reloadAll() }.keyboardShortcut("r")`

## Notes

- Use `.disabled(fileMenuActions == nil)` to avoid menu items when no focus.
- Use `.keyboardShortcut("s", modifiers: [.command])` for Cmd+S if needed, but default for String uses Cmd automatically.
- If you want to replace default Save, use `CommandGroup(replacing: .saveItem)`.
- Keep menu items in File by using `.newItem` or `.saveItem` groups rather than `.appSettings` or `.toolbar`.

Overview

This skill describes a minimal, reliable pattern for implementing macOS menu commands and keyboard shortcuts in SwiftUI apps. It focuses on using Commands, CommandGroup, and FocusedValues to wire File-menu actions (like Save All / Reload All) so shortcuts work across focused windows and views. It helps avoid common pitfalls with EnvironmentObjects and toolbar-based shortcuts.

How this skill works

The pattern exposes actionable closures via a small struct stored on FocusedValues so the active window or view provides the implementation. Commands and CommandGroup declared on the App read the focused value and invoke those closures when menu items or keyboard shortcuts are triggered. Menu items can be disabled when no focused actions exist, and groups can replace or extend standard File menu entries.

When to use it

  • Implementing File menu actions that must operate on the active window or document.
  • Wiring global app shortcuts (Cmd+S, Cmd+R, etc.) that must work regardless of focused subviews.
  • Replacing or extending default Save/Reload menu items in SwiftUI macOS apps.
  • Avoiding fragile EnvironmentObject resolution inside Commands or when menus are built early.
  • Ensuring keyboard shortcuts fire even if the action is exposed through a toolbar or custom view.

Best practices

  • Declare Commands and CommandGroup on the App with .commands { ... } and attach .keyboardShortcut to Buttons.
  • Expose a small action struct (e.g., FileMenuActions) on FocusedValues and set it on the root view with .focusedValue(...).
  • Avoid relying on @EnvironmentObject inside Commands; use @FocusedValue to resolve per-window context reliably.
  • Use .disabled(fileMenuActions == nil) to hide or disable menu items when no relevant focus exists.
  • Prefer CommandGroup(after: .newItem) or replacing: .saveItem to place items correctly in the File menu rather than adding them to toolbar or settings groups.

Example use cases

  • Save All command wired to the active editor window using FileMenuActions.saveAll and Cmd+S keyboard shortcut.
  • Reload All command that refreshes scene or document state across the focused window with Cmd+R.
  • Replacing the default Save item to call a custom batching save implemented at the window level.
  • Adding global app shortcuts that must be available only when a particular window or document type is focused.
  • Disabling Save/Reload menu items when no document window is focused to prevent no-op actions.

FAQ

Why use FocusedValues instead of EnvironmentObject for Commands?

EnvironmentObject can fail when Commands are instantiated before view env injection or when no view is focused. FocusedValues resolve per-window context and are designed for this use case.

How do I make Cmd+S trigger even if my Save button is in a toolbar?

Attach the keyboard shortcut to a menu Button in a CommandGroup rather than relying on a toolbar button. This ensures the shortcut is registered globally and invokes the focused action.