Use when implementing iOS 26 SwiftUI features - covers Liquid Glass design system, performance improvements, @Animatable macro, 3D spatial layout, scene bridging, WebView/WebPage, AttributedString rich text editing, drag and drop enhancements, and visionOS integration for iOS 26+
/plugin marketplace add CharlesWiltgen/Axiom/plugin install axiom@axiom-marketplaceThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Comprehensive guide to new SwiftUI features in iOS 26, iPadOS 26, macOS Tahoe, watchOS 26, and visionOS 26. From the Liquid Glass design system to rich text editing, these enhancements make SwiftUI more powerful across all Apple platforms.
Core principle From low level performance improvements all the way up through the buttons in your user interface, there are some major improvements across the system.
enabledBoundsaxiom-liquid-glass skill — Design principles, implementation, variants, design review pressureaxiom-liquid-glass-ref skill — App-wide adoption guide (app icons, controls, navigation, menus, windows)The new design system provides "a bright and fluid experience that's consistent across Apple platforms." Apps automatically adopt the new appearance upon recompilation - navigation containers, tab bars, and toolbars update automatically.
// No code changes required - recompile and get new design
NavigationSplitView {
List {
// Sidebar automatically gets glassy appearance on iPad/macOS
}
} detail: {
// Detail view
}
// Tab bars automatically compact on iPhone
TabView {
// Tabs get new appearance
}
.toolbar {
ToolbarItemGroup(placement: .topBarTrailing) {
Button("Up") { }
Button("Down") { }
// Fixed spacer separates button groups
Spacer(.fixed)
Button("Settings") { }
}
}
Button("Add Trip") {
addTrip()
}
.buttonStyle(.borderedProminent)
.tint(.blue)
// Liquid Glass toolbars support tinting for prominence
ScrollView {
// When content scrolls under toolbar/navigation bar,
// blur effect automatically ensures bar content remains legible
ForEach(trips) { trip in
TripRow(trip: trip)
}
}
// No code required - automatic scroll edge blur
NavigationSplitView {
List { }
.searchable(text: $searchText)
}
// Placement on NavigationSplitView automatically:
// - Bottom-aligned on iPhone (more ergonomic)
// - Top trailing corner on iPad
See swiftui-nav-ref skill Section 5.5 (iOS 26 Tab Features) for Tab(role: .search) patterns.
struct PhotoGalleryView: View {
var body: some View {
CustomPhotoGrid()
.glassBackgroundEffect() // Reflects surrounding content
}
}
Controls now have the new design automatically:
Reference "Build a SwiftUI app with the new design" (WWDC 2025) for adoption best practices and advanced customizations.
iOS 26 introduces major enhancements to Slider: custom tick marks, constrained selection ranges, current value labels, and thumb visibility control.
| Type | Purpose |
|---|---|
SliderTick<V> | Individual tick at a specific value with optional label |
SliderTickContentForEach | Iterate over collection to create multiple ticks |
SliderTickBuilder | Result builder for composing tick content |
TupleSliderTickContent | Internal type for multiple inline ticks |
SliderTickContent | Protocol that all tick types conform to |
struct SpeedSlider: View {
@State private var speed: Double = 0.5
var body: some View {
Slider(value: $speed) {
Text("Speed")
} ticks: {
SliderTick(0.2)
SliderTick(0.5)
SliderTick(0.8)
}
}
}
Slider(value: $value, in: 0...10) {
Text("Rating")
} ticks: {
SliderTick(0) { Text("Min") }
SliderTick(5) { Text("Mid") }
SliderTick(10) { Text("Max") }
}
struct TemperatureSlider: View {
@State private var temp: Float = 70
var body: some View {
let stops: [Float] = stride(from: 60, through: 80, by: 5).map { Float($0) }
Slider(value: $temp, in: 60...80) {
Text("Temperature")
} ticks: {
SliderTickContentForEach(stops, id: \.self) { value in
SliderTick(value) {
Text("\(Int(value))°")
.font(.caption2)
}
}
}
}
}
Important SliderTickContentForEach requires Data.Element to match the SliderTick<V> value type. You cannot iterate directly over custom structs.
struct Chapter {
let time: Double
let name: String
let id: UUID
}
// ERROR: Data.Element (Chapter) doesn't match SliderTick value type (Double)
SliderTickContentForEach(chapters, id: \.id) { chapter in
SliderTick(chapter.time) { Text(chapter.name) }
}
struct ChapterSlider: View {
@Binding var currentTime: Double
let chapters: [Chapter]
let duration: Double
var body: some View {
Slider(value: $currentTime, in: 0...duration) {
Text("Time")
} ticks: {
// Iterate over Double values, not Chapter structs
SliderTickContentForEach(chapters.map(\.time), id: \.self) { time in
SliderTick(time) {
// Look up chapter name for label
if let chapter = chapters.first(where: { $0.time == time }) {
Text(chapter.name)
.font(.caption2)
}
}
}
}
}
}
Why The API ties tick positions to slider values (BinaryFloatingPoint). The type system enforces this so ticks align correctly with the slider's value range.
Slider(
value: $rating,
in: 0...100,
neutralValue: 50, // Starting point / center value
enabledBounds: 20...80, // Restrict selectable range
label: { Text("Rating") },
currentValueLabel: { Text("\(Int(rating))") },
minimumValueLabel: { Text("0") },
maximumValueLabel: { Text("100") },
ticks: {
SliderTick(20) { Text("Min") }
SliderTick(50) { Text("Neutral") }
SliderTick(80) { Text("Max") }
},
onEditingChanged: { editing in
print(editing ? "Started" : "Ended")
}
)
| Parameter | Type | Purpose |
|---|---|---|
value | Binding<V> | Current slider value |
bounds | ClosedRange<V> | Full value range (default: 0...1) |
step | V.Stride | Increment between valid values |
neutralValue | V? | Starting/center point |
enabledBounds | ClosedRange<V>? | Restrict which values are selectable |
ticks | @SliderTickBuilder | Custom tick marks |
currentValueLabel | @ViewBuilder | Shows current value |
onEditingChanged | (Bool) -> Void | Called when editing starts/ends |
Slider(
value: $volume,
in: 0...10,
step: 2,
label: { Text("Volume") },
tick: { value in
// Called for each step value (0, 2, 4, 6, 8, 10)
SliderTick(value) {
Text("\(Int(value))")
}
}
)
struct MediaControlView: View {
@State private var progress: CGFloat = 0.5
var body: some View {
Slider(value: $progress)
.sliderThumbVisibility(.hidden)
.padding(.horizontal, 16)
}
}
Visibility options
.automatic — System default (usually visible).visible — Always show thumb.hidden — Hide thumbUse cases
Note On watchOS, the slider thumb is always visible regardless of this setting.
struct MediaPlayerControls: View {
@State private var currentTime: Double = 0
let duration: Double = 300 // 5 minutes
let chapters: [Chapter] = [
Chapter(time: 0, name: "Intro", id: UUID()),
Chapter(time: 60, name: "Verse 1", id: UUID()),
Chapter(time: 120, name: "Chorus", id: UUID()),
Chapter(time: 180, name: "Verse 2", id: UUID()),
Chapter(time: 240, name: "Outro", id: UUID())
]
var body: some View {
VStack {
// Time display
HStack {
Text(formatTime(currentTime))
Spacer()
Text(formatTime(duration))
}
.font(.caption)
// Slider with chapter ticks
Slider(
value: $currentTime,
in: 0...duration,
label: { Text("Playback") },
currentValueLabel: {
if let chapter = currentChapter {
Text(chapter.name)
.font(.caption)
}
},
ticks: {
SliderTickContentForEach(chapters.map(\.time), id: \.self) { time in
SliderTick(time)
}
}
)
.sliderThumbVisibility(.hidden)
}
.padding()
}
var currentChapter: Chapter? {
chapters.last { $0.time <= currentTime }
}
func formatTime(_ seconds: Double) -> String {
let mins = Int(seconds) / 60
let secs = Int(seconds) % 60
return String(format: "%d:%02d", mins, secs)
}
}
struct ContentView: View {
var body: some View {
NavigationStack {
List {
ForEach(1...20, id: \.self) { index in
Text("\(index). Item")
}
}
.safeAreaBar(edge: .bottom) {
Text("Bottom Action Bar")
.padding(.vertical, 15)
}
.scrollEdgeEffectStyle(.soft, for: .bottom)
// Alternative: .scrollEdgeEffectStyle(.hard, for: .bottom)
}
}
}
Features
safeAreaInset but with integrated blur.soft) or hard blur (.hard) via scrollEdgeEffectStyleUse cases
struct LinkView: View {
@Environment(\.openURL) var openURL
var body: some View {
let website = URL(string: "https://example.com")!
VStack {
// Old style - opens in Safari
Link(destination: website) {
Text("Open in Safari")
}
// New style - opens in-app (iOS 26+)
Button("Open In-App") {
openURL(website, prefersInApp: true)
}
.buttonStyle(.borderedProminent)
}
}
}
Key difference
Link opens in Safari appopenURL(url, prefersInApp: true) opens in SFSafariViewController-style in-app browserstruct ModalView: View {
@State private var showSheet = false
var body: some View {
Button("Show Sheet") {
showSheet.toggle()
}
.sheet(isPresented: $showSheet) {
NavigationStack {
VStack {}
.navigationTitle("Info")
.toolbar {
ToolbarSpacer(.flexible, placement: .topBarTrailing)
ToolbarItem(placement: .topBarTrailing) {
Button(role: .close) {
showSheet = false
}
}
}
}
.presentationDetents([.medium])
}
}
}
Features
Button(role: .close) renders as X icon with glass effect in toolbarsButton(role: .confirm) provides system-styled confirmation buttonUse cases
struct GlassButtonExample: View {
var body: some View {
ZStack {
Image(.background)
.resizable()
.aspectRatio(contentMode: .fill)
.ignoresSafeArea()
VStack(spacing: 16) {
Button("Clear Glass") {}
.buttonStyle(GlassButtonStyle(.clear))
Button("Regular Glass") {}
.buttonStyle(GlassButtonStyle(.glass))
Button("Tinted Glass") {}
.buttonStyle(GlassButtonStyle(.tint))
.tint(.blue)
}
.fontWeight(.bold)
.foregroundStyle(.white)
.buttonSizing(.flexible)
.font(.title)
.padding()
}
}
}
Variants
.clear — Transparent glass effect.glass — Standard glass appearance.tint — Colored glass (use with .tint() modifier)Requires iOS 26.1+ (not available in initial iOS 26.0 release)
struct ButtonLayoutExample: View {
var body: some View {
VStack(spacing: 16) {
Button("Fit Content") {}
.buttonSizing(.fit)
// Button shrinks to label size
Button("Stretch Full Width") {}
.buttonSizing(.stretch)
// Button expands to fill available space
Button("Flexible") {}
.buttonSizing(.flexible)
// Balanced between fit and stretch
}
.padding()
}
}
Options
.fit — Button fits label size.stretch — Button fills available width.flexible — Balanced sizing (context-dependent)Works with
struct SearchView: View {
@State private var searchText = ""
var body: some View {
NavigationStack {
List {
Text("User 1")
Text("User 2")
Text("User 3")
}
.navigationTitle("Search Users")
.searchable(text: $searchText)
.searchToolbarBehavior(.minimize)
.toolbar {
ToolbarSpacer(.flexible, placement: .bottomBar)
DefaultToolbarItem(kind: .search, placement: .bottomBar)
}
}
}
}
Behavior
.minimize — Search field compact when unfocused, expands on tapUse cases
.searchable(text: $searchText)
.searchPresentationToolbarBehavior(.avoidHidingContent)
Behavior
.avoidHidingContent keeps title visible during searchNote This modifier was introduced in iOS 17.1, not iOS 26, but complements the new searchToolbarBehavior modifier.
.commands {
TextEditingCommands() // Same API as macOS menu bar
CommandGroup(after: .newItem) {
Button("Add Note") {
addNote()
}
.keyboardShortcut("n", modifiers: [.command, .shift])
}
}
// Creates menu bar on iPad when people swipe down
// MIGRATION REQUIRED:
// Remove deprecated property list key in iPadOS 26:
// UIRequiresFullscreen (entire key deprecated, all values)
// For split view navigation, system automatically shows/hides columns
// based on available space during resize
NavigationSplitView {
Sidebar()
} detail: {
Detail()
}
// Adapts to resizing automatically
Reference "Elevate the design of your iPad app" (WWDC 2025)
.windowResizeAnchor(.topLeading) // Tailor where animation originates
// SwiftUI now synchronizes animation between content view size changes
// and window resizing - great for preserving continuity when switching tabs
List(trips) { trip in // 100k+ items
TripRow(trip: trip)
}
// Loads 6x faster, updates 16x faster on macOS (iOS 26+)
SwiftUI has improved scheduling of user interface updates on iOS and macOS. This improves responsiveness and lets SwiftUI do even more work to prepare for upcoming frames. All in all, it reduces the chance of your app dropping a frame while scrolling quickly at high frame rates.
ScrollView(.horizontal) {
LazyHStack {
ForEach(photoSets) { photoSet in
ScrollView(.vertical) {
LazyVStack {
ForEach(photoSet.photos) { photo in
PhotoView(photo: photo)
}
}
}
}
}
}
// Nested scrollviews now properly delay loading with lazy stacks
// Great for building photo carousels
Available lanes:
Reference "Optimize SwiftUI performance with instruments" (WWDC 2025)
Cross-reference SwiftUI Performance — Master the SwiftUI Instrument
@Observable
class TripStore {
var trips: [Trip] = []
func loadTrips() async {
trips = await TripService.fetchTrips()
// Swift 6 verifies data race safety at compile time
}
}
Benefits Find bugs in concurrent code before they affect your app
Cross-reference Swift Concurrency — Swift 6 strict concurrency patterns
Simplifies custom animations by automatically synthesizing animatableData property.
struct HikingRouteShape: Shape {
var startPoint: CGPoint
var endPoint: CGPoint
var elevation: Double
var drawingDirection: Bool // Don't want to animate this
// Tedious manual animatableData declaration
var animatableData: AnimatablePair<CGPoint.AnimatableData,
AnimatablePair<Double, CGPoint.AnimatableData>> {
get {
AnimatablePair(startPoint.animatableData,
AnimatablePair(elevation, endPoint.animatableData))
}
set {
startPoint.animatableData = newValue.first
elevation = newValue.second.first
endPoint.animatableData = newValue.second.second
}
}
}
@Animatable
struct HikingRouteShape: Shape {
var startPoint: CGPoint
var endPoint: CGPoint
var elevation: Double
@AnimatableIgnored
var drawingDirection: Bool // Excluded from animation
// animatableData automatically synthesized!
}
animatableData property@AnimatableIgnored for properties to excludeCross-reference SwiftUI Animation (swiftui-animation-ref skill) — Comprehensive animation guide covering VectorArithmetic, Animatable protocol, @Animatable macro, animation types, Transaction system, and performance optimization
struct SunPositionView: View {
@State private var timeOfDay: Double = 12.0
var body: some View {
HikingRouteView()
.overlay(alignment: sunAlignment) {
SunView()
.spatialOverlay(alignment: sunAlignment)
}
}
var sunAlignment: Alignment3D {
// Align sun in 3D space based on time of day
Alignment3D(
horizontal: .center,
vertical: .top,
depth: .back
)
}
}
Model3D(named: "WaterBottle")
.manipulable() // People can pick up and move the object
@Environment(\.sceneSnapping) var sceneSnapping
var body: some View {
Model3D(named: item.modelName)
.overlay(alignment: .bottom) {
if sceneSnapping.isSnapped {
Pedestal() // Show pedestal for items snapped to table
}
}
}
Scene bridging allows your UIKit and AppKit lifecycle apps to interoperate with SwiftUI scenes. Apps can use it to open SwiftUI-only scene types or use SwiftUI-exclusive features right from UIKit or AppKit code.
MenuBarExtra (macOS)ImmersiveSpace (visionOS)RemoteImmersiveSpace (macOS → Vision Pro)AssistiveAccess (iOS 26)Works with scene modifiers like:
.windowStyle().immersiveEnvironmentBehavior()// In your macOS app
@main
struct MyMacApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
RemoteImmersiveSpace(id: "stereoView") {
// Render stereo content on Apple Vision Pro
// Uses CompositorServices
}
}
}
Reference "What's new in Metal rendering for immersive apps" (WWDC 2025)
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
AssistiveAccessScene {
SimplifiedUI() // UI shown when iPhone is in AssistiveAccess mode
}
}
}
Reference "Customize your app for Assistive Access" (WWDC 2025)
// Show SwiftUI view in AppKit sheet
let hostingController = NSHostingController(rootView: SwiftUISettingsView())
presentAsSheet(hostingController)
// Great for incremental SwiftUI adoption
// Bridge AppKit gestures to SwiftUI
struct AppKitPanGesture: NSGestureRecognizerRepresentable {
func makeNSGestureRecognizer(context: Context) -> NSPanGestureRecognizer {
NSPanGestureRecognizer()
}
func updateNSGestureRecognizer(_ recognizer: NSPanGestureRecognizer, context: Context) {
// Update configuration
}
}
NSHostingView can now be used directly in Interface Builder for gradual SwiftUI adoption.
@Observable
class RealityEntity {
var position: SIMD3<Float>
var rotation: simd_quatf
}
struct MyView: View {
@State private var entity = RealityEntity()
var body: some View {
// SwiftUI views automatically observe changes
Text("Position: \(entity.position.x)")
}
}
// New component allows presenting SwiftUI popovers from RealityKit entities
entity.components[PopoverComponent.self] = PopoverComponent {
VStack {
Text("Next photo location")
Button("Mark Favorite") { }
}
}
Reference "Better Together: SwiftUI & RealityKit" (WWDC 2025)
WebKit now provides full SwiftUI APIs for embedding web content, eliminating the need to drop down to UIKit.
import WebKit
struct ArticleView: View {
let articleURL: URL
var body: some View {
WebView(url: articleURL)
}
}
import WebKit
struct BrowserView: View {
@State private var webPage = WebPage()
var body: some View {
VStack {
// Show page title
Text(webPage.title ?? "Loading...")
WebView(page: webPage)
HStack {
Button("Back") {
webPage.goBack()
}
.disabled(!webPage.canGoBack)
Button("Forward") {
webPage.goForward()
}
.disabled(!webPage.canGoForward)
}
}
}
}
goBack(), goForward())title, url, canGoBack, canGoForward)Reference "Meet WebKit for SwiftUI" (WWDC 2025)
SwiftUI's new support for rich text editing is great for experiences like commenting on photos. TextView now supports AttributedString!
Note The WWDC transcript uses "TextView" as editorial language. The actual SwiftUI API is TextEditor which now supports AttributedString binding for rich text editing.
struct CommentView: View {
@State private var comment = AttributedString("Enter your comment")
var body: some View {
TextEditor(text: $comment)
// Built-in text formatting controls included
// Users can apply bold, italic, underline, etc.
}
}
AttributedString preserves formattingReference "Cook up a rich text experience in SwiftUI with AttributedString" (WWDC 2025)
Cross-reference App Intents Integration (app-intents-ref skill) — AttributedString for Apple Intelligence Use Model action
struct PhotoGrid: View {
@State private var selection: Set<Photo.ID> = []
let photos: [Photo]
var body: some View {
LazyVGrid(columns: columns) {
ForEach(photos) { photo in
PhotoCell(photo: photo)
.draggable(photo) // Individual item
}
}
.dragContainer { // Container for multiple items
// Return items based on selection
selection.map { id in
photos.first { $0.id == id }
}
.compactMap { $0 }
}
}
}
.dragContainer {
// Items loaded lazily when drop occurs
// Great for expensive operations like image encoding
selectedPhotos.map { photo in
photo.transferRepresentation
}
}
.dragConfiguration(.init(supportedOperations: [.copy, .move, .delete]))
.onDragSessionUpdated { session in
if case .ended(let operation) = session.phase {
if operation == .delete {
deleteSelectedPhotos()
}
}
}
.dragPreviewFormation(.stack) // Items stack nicely on top of one another
// Other formations:
// - .default
// - .grid
// - .stack
struct PhotoLibrary: View {
@State private var selection: Set<Photo.ID> = []
let photos: [Photo]
var body: some View {
LazyVGrid(columns: columns) {
ForEach(photos) { photo in
PhotoCell(photo: photo)
}
}
.dragContainer {
selectedPhotos
}
.dragConfiguration(.init(supportedOperations: [.copy, .delete]))
.dragPreviewFormation(.stack)
.onDragSessionUpdated { session in
if case .ended(.delete) = session.phase {
deleteSelectedPhotos()
}
}
}
}
Swift Charts now supports three-dimensional plotting with Chart3D.
import Charts
struct ElevationChart: View {
let hikingData: [HikeDataPoint]
var body: some View {
Chart3D {
ForEach(hikingData) { point in
LineMark3D(
x: .value("Distance", point.distance),
y: .value("Elevation", point.elevation),
z: .value("Time", point.timestamp)
)
}
}
.chartXScale(domain: 0...10)
.chartYScale(domain: 0...3000)
.chartZScale(domain: startTime...endTime) // Z-specific modifier
}
}
Chart3D container.chartZScale(), .chartZAxis(), etc.)Reference "Bring Swift Charts to the third dimension" (WWDC 2025)
struct FavoriteLocationControl: ControlWidget {
var body: some ControlWidgetConfiguration {
StaticControlConfiguration(kind: "FavoriteLocation") {
ControlWidgetButton(action: MarkFavoriteIntent()) {
Label("Mark Favorite", systemImage: "star")
}
}
}
}
// Access from watch face or Shortcuts
Controls now appear in Control Center on Mac.
struct CountdownWidget: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(kind: "Countdown") { entry in
CountdownView(entry: entry)
}
}
}
struct CountdownView: View {
@Environment(\.levelOfDetail) var levelOfDetail
let entry: CountdownEntry
var body: some View {
VStack {
Text(entry.date, style: .timer)
if levelOfDetail == .expanded {
// Show photos when close to widget
PhotoCarousel(photos: entry.recentPhotos)
}
}
}
}
Live Activities now appear on CarPlay displays for glanceable information while driving.
Reference "What's new in widgets" (WWDC 2025)
<key>UIRequiresFullscreen</key>
<!-- Entire property list key is deprecated (all values) -->
Apps must support resizable windows on iPad.
✅ Liquid Glass design for navigation, tab bars, toolbars ✅ Bottom-aligned search on iPhone ✅ List performance improvements (6x loading, 16x updating) ✅ Scrolling performance improvements ✅ System controls (toggles, pickers, sliders) new appearance
🔧 Toolbar spacers (.fixed)
🔧 Tinted prominent buttons in toolbars
🔧 Glass effect for custom views (.glassBackgroundEffect())
🔧 Search tab role (.tabRole(.search))
🔧 iPad menu bar (.commands)
🔧 Window resize anchor (.windowResizeAnchor())
🔧 @Animatable macro for custom shapes/modifiers
🔧 WebView for web content
🔧 TextEditor with AttributedString binding
🔧 Enhanced drag and drop with .dragContainer
🔧 Slider ticks (SliderTick, SliderTickContentForEach)
🔧 Slider thumb visibility (.sliderThumbVisibility())
🔧 Safe area bars with blur (.safeAreaBar() + .scrollEdgeEffectStyle())
🔧 In-app URL opening (openURL(url, prefersInApp: true))
🔧 Close and confirm button roles (Button(role: .close))
🔧 Glass button styles (GlassButtonStyle — iOS 26.1+)
🔧 Button sizing control (.buttonSizing())
🔧 Compact search toolbar (.searchToolbarBehavior(.minimize))
.safeAreaPadding() for edge-to-edge content (iOS 17+).safeAreaPadding() with Liquid Glass materials extending edge-to-edge.padding() for internal spacing between views.padding() when content extends to screen edges (ignores notch/home indicator).safeAreaPadding() instead)Reference: See axiom-swiftui-layout-ref skill for complete .safeAreaPadding() vs .padding() guide, or axiom-liquid-glass-ref for Liquid Glass-specific safe area patterns.
AttributedString binding for TextEditorString and lose formattingAlignment3D for depth-based layouts.manipulable() for objects users should interact withSymptom App still has old design after updating to iOS 26 SDK
Symptom Search remains at top on iPhone
// ✅ CORRECT: searchable on NavigationSplitView
NavigationSplitView {
List { }
.searchable(text: $query)
}
// ❌ WRONG: searchable on List directly in non-navigation context
List { }
.searchable(text: $query)
Symptom Compile error "Type does not conform to Animatable"
// Ensure all properties are either:
// 1. VectorArithmetic conforming types (Double, CGFloat, CGPoint, etc.)
// 2. Marked with @AnimatableIgnored
@Animatable
struct MyShape: Shape {
var radius: Double // ✅ VectorArithmetic
var position: CGPoint // ✅ VectorArithmetic
@AnimatableIgnored
var fillColor: Color // ✅ Ignored (Color is not VectorArithmetic)
}
Symptom Rich text formatting disappears
// ✅ CORRECT: Binding to AttributedString
@State private var text = AttributedString("Hello")
TextEditor(text: $text)
// ❌ WRONG: Binding to String
@State private var text = "Hello"
TextEditor(text: $text) // Plain String loses formatting
Symptom Dragging to Dock trash doesn't delete items
// Must include .delete in supported operations
.dragConfiguration(.init(supportedOperations: [.copy, .delete]))
// And observe the delete event
.onDragSessionUpdated { session in
if case .ended(.delete) = session.phase {
deleteItems()
}
}
Symptom Compile error when iterating over custom types like [Chapter]
// ERROR: Cannot convert value of type 'Chapter' to expected argument type
SliderTickContentForEach(chapters, id: \.id) { chapter in
SliderTick(chapter.time) { ... }
}
SliderTickContentForEach requires Data.Element to match the SliderTick<V> value type. Extract the numeric values and look up metadata separately:
// ✅ CORRECT: Iterate over Double values
SliderTickContentForEach(chapters.map(\.time), id: \.self) { time in
SliderTick(time) {
if let chapter = chapters.first(where: { $0.time == time }) {
Text(chapter.name)
}
}
}
Why The API enforces type safety between tick positions and slider values. This is an API design constraint, not a bug.
WWDC: 2025-256
Docs: /swiftui, /swiftui/slider, /swiftui/slidertick, /swiftui/slidertickcontentforeach, /webkit, /foundation/attributedstring, /charts
Skills: axiom-swiftui-performance, axiom-liquid-glass, axiom-swift-concurrency, axiom-app-intents-ref
Last Updated Based on WWDC 2025-256 "What's new in SwiftUI" Version iOS 26+, iPadOS 26+, macOS Tahoe+, watchOS 26+, axiom-visionOS 26+
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.