toolbars
Modern SwiftUI toolbar patterns including customizable toolbars, search integration, transition effects, and platform-specific behavior. Use when implementing or customizing toolbars in SwiftUI.
What this skill does
# SwiftUI Toolbars
Modern toolbar patterns for SwiftUI apps. Covers customizable toolbars, enhanced search integration, new placements, transition effects, and platform-specific considerations.
## When This Skill Activates
Use this skill when the user:
- Wants to add or customize toolbars
- Asks about customizable/user-configurable toolbars
- Needs search field in toolbar with specific placement
- Wants toolbar item transitions or animations
- Asks about toolbar placements (bottomBar, largeSubtitle, etc.)
- Needs platform-specific toolbar behavior (iOS vs macOS)
- Wants to reposition system toolbar items (search, sidebar)
## Decision Tree
```
What toolbar feature do you need?
|
+- User-customizable toolbar (add/remove/reorder items)
| +- Use .toolbar(id:) with ToolbarItem(id:)
|
+- Search field in toolbar
| +- Minimize to button -> .searchToolbarBehavior(.minimize)
| +- Reposition search -> DefaultToolbarItem(kind: .search, placement:)
|
+- Toolbar transition/animation
| +- Zoom transition from toolbar item -> .matchedTransitionSource(id:in:)
| +- Hide glass background -> .sharedBackgroundVisibility(.hidden)
|
+- Custom subtitle area content
| +- Use ToolbarItem(placement: .largeSubtitle)
|
+- System toolbar items with custom placement
| +- DefaultToolbarItem(kind: .search/.sidebar, placement:)
```
## API Availability
| API | Minimum Version | Notes |
|-----|----------------|-------|
| `.toolbar { }` | iOS 14 | Basic toolbar |
| `ToolbarItem(placement:)` | iOS 14 | Standard placements |
| `.toolbar(id:)` | iOS 16 | Customizable toolbars |
| `ToolbarItem(id:)` | iOS 16 | Items in customizable toolbars |
| `ToolbarSpacer` | iOS 16 | Fixed and flexible spacers |
| `.searchable()` | iOS 15 | Search integration |
| `.searchToolbarBehavior(.minimize)` | iOS 17 | Minimized search button |
| `DefaultToolbarItem(kind:placement:)` | iOS 18 | Reposition system items |
| `ToolbarItem(placement: .largeSubtitle)` | iOS 18 | Subtitle area content |
| `.matchedTransitionSource(id:in:)` | iOS 18 | Toolbar transition source |
| `.sharedBackgroundVisibility()` | iOS 18 | Glass background control |
## Customizable Toolbars
Allow users to personalize toolbar items by adding, removing, and rearranging:
```swift
ContentView()
.toolbar(id: "main-toolbar") {
ToolbarItem(id: "tag") {
TagButton()
}
ToolbarItem(id: "share") {
ShareButton()
}
ToolbarSpacer(.fixed)
ToolbarItem(id: "more") {
MoreButton()
}
}
```
### Toolbar Spacers
```swift
ToolbarSpacer(.fixed) // Fixed-width space
ToolbarSpacer(.flexible) // Flexible space — pushes items apart
```
### Anti-Patterns
```swift
// ❌ Missing IDs in customizable toolbar — items can't be customized
.toolbar(id: "main") {
ToolbarItem { // No id parameter
ShareButton()
}
}
// ✅ Every item needs its own ID
.toolbar(id: "main") {
ToolbarItem(id: "share") {
ShareButton()
}
}
```
## Enhanced Search Integration
### Minimized Search
Renders search field as a compact button that expands on tap:
```swift
@State private var searchText = ""
NavigationStack {
RecipeList()
.searchable(text: $searchText)
.searchToolbarBehavior(.minimize)
}
```
### Repositioning Search
Move the default search field to a different toolbar position:
```swift
NavigationSplitView {
AllCalendarsView()
} detail: {
SelectedCalendarView()
.searchable(text: $query)
.toolbar {
ToolbarItem(placement: .bottomBar) {
CalendarPicker()
}
ToolbarItem(placement: .bottomBar) {
Invites()
}
DefaultToolbarItem(kind: .search, placement: .bottomBar)
ToolbarSpacer(placement: .bottomBar)
ToolbarItem(placement: .bottomBar) {
NewEventButton()
}
}
}
```
## System-Defined Toolbar Items
Reposition system items with custom placements:
```swift
.toolbar {
DefaultToolbarItem(kind: .search, placement: .bottomBar)
DefaultToolbarItem(kind: .sidebar, placement: .navigationBarLeading)
}
```
## Large Subtitle Placement
Place custom content in the navigation bar subtitle area:
```swift
NavigationStack {
DetailView()
.navigationTitle("Title")
.navigationSubtitle("Subtitle")
.toolbar {
ToolbarItem(placement: .largeSubtitle) {
CustomLargeNavigationSubtitle()
}
}
}
```
The `.largeSubtitle` placement takes precedence over the value provided to `navigationSubtitle(_:)`.
## Transition Effects
### Matched Transition from Toolbar
Create zoom transitions originating from a toolbar button:
```swift
struct ContentView: View {
@State private var isPresented = false
@Namespace private var namespace
var body: some View {
NavigationStack {
DetailView()
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button("Show Sheet", systemImage: "globe") {
isPresented = true
}
}
.matchedTransitionSource(id: "world", in: namespace)
}
.sheet(isPresented: $isPresented) {
SheetView()
.navigationTransition(
.zoom(sourceID: "world", in: namespace))
}
}
}
}
```
### Glass Background Control
Control the shared glass background on toolbar items:
```swift
ContentView()
.toolbar(id: "main") {
ToolbarItem(id: "build-status", placement: .principal) {
BuildStatus()
}
.sharedBackgroundVisibility(.hidden)
}
```
## Top 5 Mistakes
| # | Mistake | Fix |
|---|---------|-----|
| 1 | Missing `id` on ToolbarItem in customizable toolbar | Every item in `.toolbar(id:)` must have its own `id` parameter |
| 2 | Using `.searchToolbarBehavior(.minimize)` without `.searchable()` | Must pair with `.searchable()` modifier — `.minimize` only affects rendering |
| 3 | Putting `.matchedTransitionSource` on the Button instead of ToolbarItem | Apply `.matchedTransitionSource(id:in:)` on the `ToolbarItem`, not its content |
| 4 | Using `.largeSubtitle` alongside `.navigationSubtitle()` expecting both to show | `.largeSubtitle` takes precedence — the subtitle modifier value is hidden |
| 5 | Forgetting `placement:` on DefaultToolbarItem | Without explicit placement, system items use their default position |
## Platform Considerations
| Platform | Recommendations |
|----------|----------------|
| **iOS** | Bottom bar useful on iPhones. Use `.searchToolbarBehavior(.minimize)` for space efficiency. |
| **iPadOS** | Customizable toolbars valuable in productivity apps. Consider keyboard shortcuts. |
| **macOS** | Users expect toolbar customization. Use spacers for logical groupings. |
## Review Checklist
### Customizable Toolbars
- [ ] `.toolbar(id:)` has a unique, stable string identifier
- [ ] Every `ToolbarItem` within has its own unique `id`
- [ ] Spacers used to create logical groups of related items
- [ ] Toolbar tested with customization panel (long-press on iPadOS, right-click on macOS)
### Search Integration
- [ ] `.searchable()` paired with appropriate `.searchToolbarBehavior()`
- [ ] Search placement makes sense for the platform (bottom bar on iOS, toolbar on macOS)
- [ ] `DefaultToolbarItem(kind: .search)` used when repositioning is needed
### Transitions
- [ ] `.matchedTransitionSource` applied to `ToolbarItem`, not its content view
- [ ] Namespace declared with `@Namespace` at the view level
- [ ] Source ID matches between `.matchedTransitionSource` and `.navigationTransition(.zoom)`
### Platform
- [ ] Toolbar layouts tested on both iOS and macOS (if multiplatform)
- [ ] Bottom bar items appropriate for small screens
- [ ] CustomizaRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.