Source profileQuality 67/100

dpearson2699/swift-ios-skills/skills/focus-engine/SKILL.md

focus-engine

Implements keyboard, directional, and scene-level focus behavior across SwiftUI and UIKit. Use when managing @FocusState, defaultFocus, focused values, focusable interactions, focus sections, tvOS geometric focus and Siri Remote navigation, watchOS Digital Crown input, visionOS connected-device focus versus gaze hover/input targets, macOS key view loop and Full Keyboard Access, focus restoration after presentation changes, custom focus routing with UIFocusGuide, or debugging focus with UIFocusDe

Source repository stars
933
Declared platforms
0
Static risk flags
0
Last source update
2026-07-15
Source checked
2026-07-28

Decision brief

What it does—and where it fits

Focus behavior for SwiftUI and UIKit apps targeting iOS 26+, iPadOS, macOS, tvOS, and visionOS connected-input paths. Covers keyboard focus, directional focus, scene-focused values, focus restoration, and UIKit focus guides. focusSection() guidance in this skill applies to macOS…

Best for

  • Use when managing @FocusState, defaultFocus, focused values, focusable interactions, focus sections, tvOS geometric focus and Siri Remote navigation, watchOS Digital Crown input, visionOS connected-device focus versus g…

Not for

  • Mixing accessibility focus and keyboard or directional focus in the same mental model.
  • Storing @FocusState in shared models instead of the owning view.

Compatibility matrix

Platform support, with evidence labels

PlatformStatusEvidenceWhat to check
CodexNot declaredNo explicit evidencePortability before use
Claude CodeNot declaredNo explicit evidencePortability before use
CursorNot declaredNo explicit evidencePortability before use
Gemini CLINot declaredNo explicit evidencePortability before use
Open the compatibility checker

Installation

Inspect first. Install second.

The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

Source-detected install commandSource
npx skills add https://github.com/dpearson2699/swift-ios-skills --skill "skills/focus-engine"
Safe inspection promptEditorial

Inspect the Agent Skill "focus-engine" from https://github.com/dpearson2699/swift-ios-skills/blob/90c9573272531337962fbb3505036d61ed23389a/skills/focus-engine/SKILL.md at commit 90c9573272531337962fbb3505036d61ed23389a. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

Workflow

What the source asks the agent to do

  1. 01

    Review Checklist

    [ ] @FocusState is local to the view that owns the controls

    [ ] @FocusState is local to the view that owns the controls[ ] Initial focus target is explicit when the screen needs one[ ] Focus movement between fields or groups is deterministic
  2. 02

    SwiftUI FocusState

    Use @FocusState to read and write focus placement inside a scene. Use Bool for a single target or an optional Hashable enum for multiple targets.

    Use @FocusState to read and write focus placement inside a scene. Use Bool for a single target or an optional Hashable enum for multiple targets.Keep focus state local to the view that owns the focusable controls.
  3. 03

    Default Focus

    Use .defaultFocus to set the preferred initial focus region or control when a view appears or when focus is reassigned automatically.

    Use .defaultFocus to set the preferred initial focus region or control when a view appears or when focus is reassigned automatically.Prefer one clear default destination per screen or focus region.
  4. 04

    Focused Values and Scene Values

    Use focused values to expose state from the currently focused view. Use scene-focused values when commands or scene-wide UI should keep access to the value even after focus moves within that scene.

    Use focused values to expose state from the currently focused view. Use scene-focused values when commands or scene-wide UI should keep access to the value even after focus moves within that scene.Use this pattern for menus, commands, and toolbars that need to act on the focused scene's current content.
  5. 05

    Focusable Interactions

    Use .focusable(:interactions:) on custom SwiftUI views that should participate in keyboard or directional focus.

    Use .focusable(:interactions:) on custom SwiftUI views that should participate in keyboard or directional focus.Prefer semantic Button, Toggle, TextField, and other system controls before making arbitrary gesture-driven views focusable. Use .focusable(interactions: .activate) for custom button-like controls only when a semantic c…

Permission review

Static risk signals and limitations

No configured static risk pattern was detected

This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.

Evidence record

Why each signal appears

EvidenceSourceComputedTestedEditorial
SignalValueEvidence typeMeaning
Quality score67/100ComputedDocumentation, specificity, maintenance, and trust rules
Repository stars933SourceRepository attention, not individual Skill quality
Compatibility0 platformsSourceDeclared in the catalog source record
Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

Pinned source

Provenance and original SKILL.md

Repository
dpearson2699/swift-ios-skills
Skill path
skills/focus-engine/SKILL.md
Commit
90c9573272531337962fbb3505036d61ed23389a
License
NOASSERTION
Collected
2026-07-28
Default branch
main
View the original SKILL.md

Focus Engine

Focus behavior for SwiftUI and UIKit apps targeting iOS 26+, iPadOS, macOS, tvOS, and visionOS connected-input paths. Covers keyboard focus, directional focus, scene-focused values, focus restoration, and UIKit focus guides. focusSection() guidance in this skill applies to macOS and tvOS. visionOS gaze-driven hover is an input affordance, not focus. Accessibility-specific focus for VoiceOver and Switch Control lives in the ios-accessibility skill.

When a request mixes focus with accessibility or spatial input, keep the boundary explicit:

  • Use this skill for keyboard, remote, game-controller, and scene focus behavior.
  • For visionOS, describe gaze, direct touch, and pointer targeting as hover/input affordances, not focus.
  • For VoiceOver, Switch Control, Voice Control, or accessibility element ordering, give only a brief handoff to ios-accessibility.

Contents

SwiftUI FocusState

Use @FocusState to read and write focus placement inside a scene. Use Bool for a single target or an optional Hashable enum for multiple targets.

struct LoginView: View {
    enum Field: Hashable { case email, password }

    @State private var email = ""
    @State private var password = ""
    @FocusState private var focusedField: Field?

    var body: some View {
        Form {
            TextField("Email", text: $email)
                .focused($focusedField, equals: .email)

            SecureField("Password", text: $password)
                .focused($focusedField, equals: .password)
        }
        .onAppear { focusedField = .email }
        .onSubmit {
            switch focusedField {
            case .email: focusedField = .password
            case .password, nil: submit()
            }
        }
    }
}

Keep focus state local to the view that owns the focusable controls.

Default Focus

Use .defaultFocus to set the preferred initial focus region or control when a view appears or when focus is reassigned automatically.

struct SidebarView: View {
    enum Target: Hashable { case library, settings }
    @FocusState private var focusedTarget: Target?

    var body: some View {
        VStack {
            Button("Library") { }
                .focused($focusedTarget, equals: .library)

            Button("Settings") { }
                .focused($focusedTarget, equals: .settings)
        }
        .defaultFocus($focusedTarget, .library)
    }
}

Prefer one clear default destination per screen or focus region.

Focused Values and Scene Values

Use focused values to expose state from the currently focused view. Use scene-focused values when commands or scene-wide UI should keep access to the value even after focus moves within that scene.

struct SelectedRecipeKey: FocusedValueKey {
    typealias Value = Binding<Recipe>
}

extension FocusedValues {
    var selectedRecipe: Binding<Recipe>? {
        get { self[SelectedRecipeKey.self] }
        set { self[SelectedRecipeKey.self] = newValue }
    }
}

struct RecipeDetailView: View {
    @Binding var recipe: Recipe

    var body: some View {
        Text(recipe.title)
            .focusedSceneValue(\.selectedRecipe, $recipe)
    }
}

Use this pattern for menus, commands, and toolbars that need to act on the focused scene's current content.

Focusable Interactions

Use .focusable(_:interactions:) on custom SwiftUI views that should participate in keyboard or directional focus.

struct SelectableCard: View {
    let title: String
    let action: () -> Void
    @FocusState private var isFocused: Bool

    var body: some View {
        Button(action: action) {
            RoundedRectangle(cornerRadius: 12)
                .fill(isFocused ? Color.accentColor.opacity(0.15) : .clear)
                .overlay { Text(title) }
        }
        .buttonStyle(.plain)
        .focusable(interactions: .activate)
        .focused($isFocused)
    }
}

Prefer semantic Button, Toggle, TextField, and other system controls before making arbitrary gesture-driven views focusable. Use .focusable(interactions: .activate) for custom button-like controls only when a semantic control cannot express the UI. Reserve broader interactions for views that genuinely need editing or multiple focus-driven behaviors.

Focus Sections

Use focusSection() on macOS 13+ and tvOS 15+ to guide directional movement across groups of focusable descendants in uneven layouts.

struct TVLibraryView: View {
    var body: some View {
        HStack {
            VStack {
                Button("Recent") { }
                Button("Favorites") { }
                Button("Downloaded") { }
            }
            .focusSection()

            VStack {
                Button("Featured") { }
                Button("Top Picks") { }
                Button("Continue Watching") { }
            }
            .focusSection()
        }
    }
}

Use focus sections on macOS and tvOS when default left/right or up/down movement skips the intended group.

Focus Restoration

After dismissing a sheet, popover, or transient overlay, return focus to a stable trigger or logical next target.

struct FiltersView: View {
    @State private var showSheet = false
    @FocusState private var isFilterButtonFocused: Bool

    var body: some View {
        Button("Filters") { showSheet = true }
            .focused($isFilterButtonFocused)
            .sheet(isPresented: $showSheet) {
                FilterEditor()
                    .onDisappear {
                        Task { @MainActor in
                            isFilterButtonFocused = true
                        }
                    }
            }
    }
}

Restore focus intentionally whenever presentation changes would otherwise leave users disoriented.

UIKit Focus Guides

Use UIFocusGuide when UIKit or tvOS layouts need custom routing across empty space or awkward geometry.

final class DashboardViewController: UIViewController {
    private let focusGuide = UIFocusGuide()
    @IBOutlet private weak var leadingButton: UIButton!
    @IBOutlet private weak var trailingButton: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addLayoutGuide(focusGuide)
        focusGuide.preferredFocusEnvironments = [trailingButton]

        NSLayoutConstraint.activate([
            focusGuide.leadingAnchor.constraint(equalTo: leadingButton.trailingAnchor),
            focusGuide.trailingAnchor.constraint(equalTo: trailingButton.leadingAnchor),
            focusGuide.topAnchor.constraint(equalTo: leadingButton.topAnchor),
            focusGuide.bottomAnchor.constraint(equalTo: leadingButton.bottomAnchor)
        ])
    }
}

UIFocusGuide is invisible and not a view. Use it to redirect focus without adding decorative UI.

Common Mistakes

  1. Mixing accessibility focus and keyboard or directional focus in the same mental model.
  2. Storing @FocusState in shared models instead of the owning view.
  3. Setting multiple competing default focus targets on one screen.
  4. Using .focusable() on decorative views.
  5. Forgetting focus restoration after sheets, popovers, or custom overlays.
  6. Reaching for UIFocusGuide before trying focusSection() on macOS or tvOS, or better layout grouping in SwiftUI.
  7. Using gesture handlers for primary actions on custom focusable controls instead of a semantic Button when possible.
  8. Treating visionOS gaze hover as focus; reserve focus guidance for connected input such as keyboards and game controllers.

Review Checklist

  • @FocusState is local to the view that owns the controls
  • Initial focus target is explicit when the screen needs one
  • Focus movement between fields or groups is deterministic
  • focusedSceneValue or related focused-value APIs are used when commands need current scene state
  • Custom controls opt into focus only when they are truly interactive
  • focusSection() is used for uneven directional layouts on macOS or tvOS before dropping to UIKit
  • Focus returns to a stable element after temporary presentations dismiss
  • UIFocusGuide geometry and preferred destinations match the intended route
  • visionOS guidance distinguishes connected-device focus from gaze-driven hover or RealityKit input targets
  • Accessibility focus concerns are handled in ios-accessibility, not mixed into keyboard-directional focus logic

References