axiom-swiftui-layout
Use when layouts need to adapt to different screen sizes, iPad multitasking, or iOS 26 free-form windows — decision trees for ViewThatFits vs AnyLayout vs onGeometryChange, size class limitations, and anti-patterns preventing device-based layout mistakes
Best use case
axiom-swiftui-layout is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Use when layouts need to adapt to different screen sizes, iPad multitasking, or iOS 26 free-form windows — decision trees for ViewThatFits vs AnyLayout vs onGeometryChange, size class limitations, and anti-patterns preventing device-based layout mistakes
Teams using axiom-swiftui-layout should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/axiom-swiftui-layout/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How axiom-swiftui-layout Compares
| Feature / Agent | axiom-swiftui-layout | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Use when layouts need to adapt to different screen sizes, iPad multitasking, or iOS 26 free-form windows — decision trees for ViewThatFits vs AnyLayout vs onGeometryChange, size class limitations, and anti-patterns preventing device-based layout mistakes
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# SwiftUI Adaptive Layout
## Overview
Discipline-enforcing skill for building layouts that respond to available space rather than device assumptions. Covers tool selection, size class limitations, iOS 26 free-form windows, and common anti-patterns.
**Core principle:** Your layout should work correctly if Apple ships a new device tomorrow, or if iPadOS adds a new multitasking mode next year. Respond to your container, not your assumptions about the device.
## When to Use This Skill
- "How do I make this layout work on iPad and iPhone?"
- "Should I use GeometryReader or ViewThatFits?"
- "My layout breaks in Split View / Stage Manager"
- "Size classes aren't giving me what I need"
- "Designer wants different layout for portrait vs landscape"
- "Preparing app for iOS 26 window resizing"
## Decision Tree
```
"I need my layout to adapt..."
│
├─ TO AVAILABLE SPACE (container-driven)
│ │
│ ├─ "Pick best-fitting variant"
│ │ → ViewThatFits
│ │
│ ├─ "Animated switch between H↔V"
│ │ → AnyLayout + condition
│ │
│ ├─ "Read size for calculations"
│ │ → onGeometryChange (iOS 16+)
│ │
│ └─ "Custom layout algorithm"
│ → Layout protocol
│
├─ TO PLATFORM TRAITS
│ │
│ ├─ "Compact vs Regular width"
│ │ → horizontalSizeClass (⚠️ iPad limitations)
│ │
│ ├─ "Accessibility text size"
│ │ → dynamicTypeSize.isAccessibilitySize
│ │
│ └─ "Platform differences"
│ → #if os() / Environment
│
└─ TO WINDOW SHAPE (aspect ratio)
│
├─ "Portrait vs Landscape semantics"
│ → Geometry + custom threshold
│
├─ "Auto show/hide columns"
│ → NavigationSplitView (automatic in iOS 26)
│
└─ "Window lifecycle"
→ @Environment(\.scenePhase)
```
## Tool Selection
### Quick Decision
```
Do you need a calculated value (width, height)?
├─ YES → onGeometryChange
└─ NO → Do you need animated transitions?
├─ YES → AnyLayout + condition
└─ NO → ViewThatFits
```
### When to Use Each Tool
| I need to... | Use this | Not this |
|-------------|----------|----------|
| Pick between 2-3 layout variants | `ViewThatFits` | `if size > X` |
| Switch H↔V with animation | `AnyLayout` | Conditional HStack/VStack |
| Read container size | `onGeometryChange` | `GeometryReader` |
| Adapt to accessibility text | `dynamicTypeSize` | Fixed breakpoints |
| Detect compact width | `horizontalSizeClass` | `UIDevice.idiom` |
| Detect narrow window on iPad | Geometry + threshold | Size class alone |
| Hide/show sidebar | `NavigationSplitView` | Manual column logic |
| Custom layout algorithm | `Layout` protocol | Nested GeometryReaders |
---
## Pattern 1: ViewThatFits
**Use when:** You have 2-3 layout variants and want SwiftUI to pick the first that fits.
```swift
ViewThatFits {
// First choice: horizontal
HStack {
Image(systemName: "star")
Text("Favorite")
Spacer()
Button("Add") { }
}
// Fallback: vertical
VStack {
HStack {
Image(systemName: "star")
Text("Favorite")
}
Button("Add") { }
}
}
```
**Limitation:** ViewThatFits doesn't expose which variant was chosen. If you need that state for other views, use AnyLayout instead.
---
## Pattern 2: AnyLayout for Animated Switching
**Use when:** You need animated transitions between layouts, or need to know current layout state.
```swift
struct AdaptiveStack<Content: View>: View {
@Environment(\.horizontalSizeClass) var sizeClass
let content: Content
var layout: AnyLayout {
sizeClass == .compact
? AnyLayout(VStackLayout(spacing: 12))
: AnyLayout(HStackLayout(spacing: 20))
}
var body: some View {
layout {
content
}
.animation(.default, value: sizeClass)
}
}
```
**For Dynamic Type:**
```swift
@Environment(\.dynamicTypeSize) var dynamicTypeSize
var layout: AnyLayout {
dynamicTypeSize.isAccessibilitySize
? AnyLayout(VStackLayout())
: AnyLayout(HStackLayout())
}
```
---
## Pattern 3: onGeometryChange (Preferred for Geometry)
**Use when:** You need actual dimensions for calculations. Preferred over GeometryReader.
```swift
struct ResponsiveGrid: View {
@State private var columnCount = 2
var body: some View {
LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: columnCount)) {
ForEach(items) { item in
ItemView(item: item)
}
}
.onGeometryChange(for: Int.self) { proxy in
max(1, Int(proxy.size.width / 150))
} action: { newCount in
columnCount = newCount
}
}
}
```
**For aspect ratio detection (iPad "orientation"):**
```swift
struct WindowShapeReader: View {
@State private var isWide = true
var body: some View {
content
.onGeometryChange(for: Bool.self) { proxy in
proxy.size.width > proxy.size.height * 1.2
} action: { newValue in
isWide = newValue
}
}
}
```
---
## Pattern 4: GeometryReader (When Necessary)
**Use when:** You need geometry AND are on iOS 15 or earlier, OR need geometry during layout phase (not just as side effect).
```swift
// ✅ CORRECT: Constrained GeometryReader
VStack {
GeometryReader { geo in
Text("Width: \(geo.size.width)")
}
.frame(height: 44) // MUST constrain!
Button("Next") { }
}
// ❌ WRONG: Unconstrained (greedy)
VStack {
GeometryReader { geo in
Text("Width: \(geo.size.width)")
}
// Takes all available space, crushes siblings
Button("Next") { }
}
```
---
## Size Class Truth Table (iPad)
| Configuration | Horizontal | Vertical |
|--------------|------------|----------|
| Full screen portrait | `.regular` | `.regular` |
| Full screen landscape | `.regular` | `.regular` |
| 70% Split View | `.regular` | `.regular` |
| 50% Split View | `.regular` | `.regular` |
| 33% Split View | `.compact` | `.regular` |
| Slide Over | `.compact` | `.regular` |
| With keyboard | (unchanged) | (unchanged) |
**Key insight:** Size class only goes `.compact` on iPad at ~33% width or Slide Over. For finer control, use geometry.
---
## iOS 26 Free-Form Windows
### What Changed
| Before iOS 26 | iOS 26+ |
|---------------|---------|
| Fixed Split View sizes | Free-form drag-to-resize |
| `UIRequiresFullScreen` allowed | **Deprecated** |
| No menu bar on iPad | Menu bar via `.commands` |
| Manual column visibility | `NavigationSplitView` auto-adapts |
### Apple's Guideline
> "Resizing an app should not permanently alter its layout. Be opportunistic about reverting back to the starting state whenever possible."
**Translation:** Don't save layout state based on window size. When window returns to original size, layout should too.
### NavigationSplitView Auto-Adaptation
```swift
// iOS 26: Columns automatically show/hide
NavigationSplitView {
Sidebar()
} content: {
ContentList()
} detail: {
DetailView()
}
// No manual columnVisibility management needed
```
### Migration Checklist
- [ ] Remove `UIRequiresFullScreen` from Info.plist
- [ ] Test at arbitrary window sizes (not just 33/50/66%)
- [ ] Verify layout doesn't "stick" after resize
- [ ] Add menu bar commands for common actions
- [ ] Test Window Controls don't overlap toolbar items
---
## Anti-Patterns
### ❌ Device Orientation Observer
```swift
// ❌ WRONG: Reports device, not window
NotificationCenter.default.addObserver(
forName: UIDevice.orientationDidChangeNotification, ...
)
let orientation = UIDevice.current.orientation
if orientation.isLandscape { ... }
```
**Why it fails:** Reports physical device orientation, not window shape. Wrong in Split View, Stage Manager, iOS 26.
**Fix:** Use `onGeometryChange` to read actual window dimensions.
### ❌ Screen Bounds
```swift
// ❌ WRONG: Returns full screen, not your window
let width = UIScreen.main.bounds.width
if width > 700 { useWideLayout() }
```
**Why it fails:** In multitasking, your app may only have 40% of the screen.
**Fix:** Read your view's actual container size.
### ❌ Device Model Checks
```swift
// ❌ WRONG: Breaks on new devices, wrong in multitasking
if UIDevice.current.userInterfaceIdiom == .pad {
useWideLayout()
}
```
**Why it fails:** iPad in 1/3 Split View is narrower than iPhone 14 Pro Max landscape.
**Fix:** Respond to available space, not device identity.
### ❌ Unconstrained GeometryReader
```swift
// ❌ WRONG: GeometryReader is greedy
VStack {
GeometryReader { geo in
Text("Size: \(geo.size)")
}
Button("Next") { } // Crushed
}
```
**Fix:** Constrain with `.frame()` or use `onGeometryChange`.
### ❌ Size Class as Orientation Proxy
```swift
// ❌ WRONG: iPad is .regular in both orientations
var isLandscape: Bool {
horizontalSizeClass == .regular // Always true on iPad!
}
```
**Fix:** Calculate from actual geometry if you need aspect ratio.
---
## Pressure Scenarios
### "Designer wants iPhone-specific layout"
**Temptation:** `if UIDevice.current.userInterfaceIdiom == .phone`
**Response:** "I'll implement these as 'compact' and 'regular' layouts that switch based on available space. The iPhone layout will appear on iPad when the window is narrow. This future-proofs us for Stage Manager and iOS 26."
### "Just use GeometryReader, it's fine"
**Temptation:** Wrap everything in GeometryReader.
**Response:** "GeometryReader has known layout side effects — it expands greedily. `onGeometryChange` reads the same data without affecting layout. It's backported to iOS 16."
### "Size classes worked before"
**Temptation:** Force everything through size class.
**Response:** "Size classes are coarse. iPad is `.regular` in both orientations. I'll use size class for broad categories and geometry for precise thresholds."
### "We don't support iPad multitasking"
**Temptation:** `UIRequiresFullScreen = true`
**Response:** "Apple deprecated full-screen-only in iOS 26. Even without active Split View support, the app can't break when resized. Space-based layout costs the same."
---
## Resources
**WWDC**: 2025-208, 2024-10074, 2022-10056
**Skills**: axiom-swiftui-layout-ref, axiom-swiftui-debugging, axiom-liquid-glassRelated Skills
dashboard-layout-planner
Dashboard Layout Planner - Auto-activating skill for Data Analytics. Triggers on: dashboard layout planner, dashboard layout planner Part of the Data Analytics skill category.
Expo UI SwiftUI
`@expo/ui/swift-ui` package lets you use SwiftUI Views and modifiers in your app.
hig-components-layout
Apple Human Interface Guidelines for layout and navigation components. Use this skill when the user asks about sidebar, split view, tab bar, tab view, scroll view, window design, panel, list view, table view, column view, outline view, navigation structure, app layout, boxes, ornaments, or organizing content hierarchically in Apple apps. Also use when the user says how should I organize my app, what navigation pattern should I use, my layout breaks on iPad, how do I build a sidebar, should I use tabs or a sidebar, or my app doesn't adapt to different screen sizes. Cross-references: hig-foundations for layout/spacing principles, hig-platforms for platform-specific navigation, hig-patterns for multitasking and full-screen, hig-components-content for content display.
avalonia-layout-zafiro
Guidelines for modern Avalonia UI layout using Zafiro.Avalonia, emphasizing shared styles, generic components, and avoiding XAML redundancy.
writing-page-layout
Use this skill when you need to write code for a page layout in the Next.js
swiftui-view-refactor
Refactor and review SwiftUI view files for consistent structure, dependency injection, and Observation usage. Use when asked to clean up a SwiftUI view’s layout/ordering, handle view models safely (non-optional when possible), or standardize how dependencies and @Observable state are initialized and passed.
swiftui-ui-patterns
Best practices and example-driven guidance for building SwiftUI views and components. Use when creating or refactoring SwiftUI UI, designing tab architecture with TabView, composing screens, or needing component-specific patterns and examples.
swiftui-performance-audit
Audit and improve SwiftUI runtime performance from code review and architecture. Use for requests to diagnose slow rendering, janky scrolling, high CPU/memory usage, excessive view updates, or layout thrash in SwiftUI apps, and to provide guidance for user-run Instruments profiling when code review alone is insufficient.
swiftui-liquid-glass
Implement, review, or improve SwiftUI features using the iOS 26+ Liquid Glass API. Use when asked to adopt Liquid Glass in new SwiftUI UI, refactor an existing feature to Liquid Glass, or review Liquid Glass usage for correctness, performance, and design alignment.
axiom-audit
Audit Axiom logs to identify and prioritize errors and warnings, research probable causes, and flag log smells. Use when user asks to check Axiom logs, analyze production errors, investigate log issues, or audit logging patterns.
swiftui-patterns
SwiftUI architecture patterns, state management with @Observable, view composition, navigation, performance optimization, and modern iOS/macOS UI best practices.
Axiom — Serverless Log Analytics
## Overview