Skip to content
Mobile
Skill

/tipkit

Implement and review Apple TipKit feature-discovery UI for iOS 17+ apps. Use when adding or auditing in-app tips, contextual help, coach marks, Tip, TipView, popoverTip, rules, events, actions, display frequency, testing overrides, reusable tip identifiers, or iOS 18+ TipGroup

From plugin
swift-ios-skills
1.3k86 skills1 MCP

Claude Code

$ npx -y skills add dpearson2699/swift-ios-skills --skill tipkit --agent claude-code

SKILL.md

tipkit.SKILL.md
name: tipkit
description: "Implement and review Apple TipKit feature-discovery UI for iOS 17+ apps. Use when adding or auditing in-app tips, contextual help, coach marks, Tip, TipView, popoverTip, rules, events, actions, display frequency, testing overrides, reusable tip identifiers, or iOS 18+ TipGroup and CloudKit tip sync; avoid for generic SwiftUI navigation or layout outside tip presentation."

TipKit

Use TipKit for small, contextual feature-discovery moments: inline tips, popover tips, rule-gated education, and lightweight coach marks. Keep generic SwiftUI architecture, navigation, layout, and long first-run onboarding flows in their sibling skills unless TipKit presentation is the core issue.

Contents

  • [Availability](#availability)
  • [Configure TipKit](#configure-tipkit)
  • [Design Good Tips](#design-good-tips)
  • [Define Tips](#define-tips)
  • [Present Tips](#present-tips)
  • [Rules and Events](#rules-and-events)
  • [Options and Invalidation](#options-and-invalidation)
  • [Actions and Styles](#actions-and-styles)
  • [Tip Groups](#tip-groups)
  • [Testing](#testing)
  • [Common Mistakes](#common-mistakes)
  • [Review Checklist](#review-checklist)
  • [References](#references)

Availability

TipKit's core `Tip`, `TipView`, `popoverTip`, rules, events, options, and testing overrides are available on iOS 17+, iPadOS 17+, macOS 14+, tvOS 17+, watchOS 10+, and visionOS 1+.

Gate newer APIs explicitly:

| API | Availability | Use | | --- | --- | --- | | `TipGroup` | iOS 18+ | Group or sequence tips; apply the [Tip Groups](#tip-groups) decision. | | `.cloudKitContainer(...)` | iOS 18+ | Sync tip state, parameters, events, and display counts across devices. | | `MaxDisplayDuration` | iOS 18+ | Automatically invalidate after cumulative display time. | | `resetEligibility()` | iOS 26+ | Make a previously invalidated tip eligible again without resetting the datastore. |

Configure TipKit

Call `Tips.configure(_:)` once during app initialization, before any tip can display. Do not configure TipKit from a view's `onAppear` or `.task`.

import SwiftUI
import TipKit

@main
struct MyApp: App {
    init() {
        do {
            try Tips.configure([
                .datastoreLocation(.applicationDefault),
                .displayFrequency(.daily)
            ])
        } catch {
            assertionFailure("TipKit configuration failed: \(error)")
        }
    }

    var body: some Scene {
        WindowGroup { ContentView() }
    }
}

Use `.datastoreLocation(.groupContainer(identifier:))` only when an app and extension or app-group members intentionally share tip state. Keep option settings consistent across app-group members because TipKit persists option state with the tip record.

CloudKit Sync

Use CloudKit sync only on iOS 18+ and later. Enable iCloud + CloudKit and Background Modes > Remote notifications, then pass a container:

try Tips.configure([
    .cloudKitContainer(.named("iCloud.com.example.app.tips"))
])

Prefer a dedicated container with a `.tips` suffix. `.automatic` uses the first entitled `.tips` container when present, then falls back to the primary container.

Design Good Tips

Tips are small, transient help. Use them for features people can understand and try in a few simple steps. If the flow needs a long explanation, multiple screens, or critical safety/error information, use a tutorial, alert, inline warning, or onboarding flow instead.

Follow HIG-aligned defaults:

  • Keep titles short, direct, and action-oriented.
  • Use one or two sentences; avoid promotional or unrelated copy.
  • Place tips near the feature they explain.
  • Prefer inline tips when hiding nearby UI would interrupt the task.
  • Prefer popover tips when preserving the current layout matters and the tip can

point to a specific control.

  • Use rules and display frequency so only the right audience sees each tip.
  • Avoid repeating an icon in the tip when the popover already points to that icon.

Define Tips

`Tip` conforms to `Identifiable` and `Sendable`. Provide `title` at minimum; add `message`, `image`, `actions`, `rules`, `options`, and `id` only when they improve the feature-discovery moment.

import TipKit

struct FavoriteTip: Tip {
    var title: Text { Text("Save to Favorites") }
    var message: Text? { Text("Tap the heart to keep items for quick access.") }
    var image: Image? { Image(systemName: "heart.fill") }
}

By default, TipKit uses the tip type name as `id`. Override `id` for reusable tips whose persisted state should vary by content:

struct NewItemTip: Tip {
    let itemID: Item.ID

    var id: String { "NewItemTip-\(itemID)" }
    var title: Text { Text("New Item Available") }
}

Use stable, concrete identifiers. Do not derive IDs from transient copy or unstable ordering.

Present Tips

Use `TipView` for inline tips:

let favoriteTip = FavoriteTip()

VStack {
    TipView(favoriteTip, arrowEdge: .bottom)
    ItemListView()
}

Use `.popoverTip` when the tip should point to a control:

Button {
    toggleFavorite()
    favoriteTip.invalidate(reason: .actionPerformed)
} label: {
    Image(systemName: "heart")
}
.popoverTip(favoriteTip, arrowEdge: .top)

Rules and Events

Rules are ANDed together. A tip becomes eligible only when every rule passes.

Use `@Parameter` for persisted app state:

struct FavoriteTip: Tip {
    @Parameter static var hasSeenList = false

    var title: Text { Text("Save to Favorites") }

    var rules: [Rule] {
        #Rule(Self.$hasSeenList) { $0 == true }
    }
}

Use `Tips.Event` for repeated user actions. TipKit queries the most recent 1000 donations by default, so keep event rules bounded and intentional.

struct ShortcutTip: Tip {
    static let manualSaveEvent = Tips.Event(id: "manualSave")

    var title: Text { Text("Save Faster") }

    var rules: [Rule] {
        #Rule(Self.manualSaveEvent) {
            $0.donations.donatedWithi
Read more
@dpearson2699
Ships withswift-ios-skills

86 agent skills optimized for iOS 26+ development with Swift 6.3 and modern Apple frameworks.

1.3k86 skills1 MCP
Get the whole plugin

Stars on GitHub

Momentum

stars in total
1.3k
Star history of dpearson2699/swift-ios-skills on GitHub, a chart by star-history.com

Other skills on swift-ios-skills.

alarmkit

alarmkit

Implement AlarmKit alarms and countdown timers for iOS and iPadOS with Lock Screen, Dynamic Island, StandBy, and paired Apple…

app-clips

app-clips

Build iOS App Clips with invocation URLs, App Clip Codes, NFC, QR codes, Safari banners, Maps, Messages, target setup, App Store…

More skills from other plugins.

deep-code-review

deep-code-review

In-depth design-focused code review - understands codebase context before evaluating PR changes, posts structured feedback to…

expo1d53k
@expo@expoInstall Skill
modlens

modlens

Plug-in vision for text-only models. Hard rule: when a file path or URL with an image extension (.png, .jpg, .jpeg, .webp, .gif,…

modlens2w4.6k
@liustack@liustackInstall Skill
appllama-app-design-skill

appllama-app-design-sk…

Build native-feeling, benchmark-quality mobile app screens (Expo / React Native). Use when designing or implementing any mobile…

appllama2mo3.9k
@appllama@appllamaInstall Skill

Questions about tipkit.

Which coding agents can use tipkit?
tipkit installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.