swiftui-sheet-keyboard-animations
Installation
SKILL.md
SwiftUI Sheet + Keyboard Choreography
Present a sheet with the keyboard rising as one motion (iMessage-compose style), and dismiss them together — in pure-ish SwiftUI.
Why naive approaches fail (all observed, not hypothetical)
| Attempt | What actually happens |
|---|---|
draftFocused = true after a delay (300–500ms) |
Works, but visibly staggered: sheet settles, THEN keyboard pops and re-lifts the input bar — an up-then-down bounce |
draftFocused = true immediately in .task/.onAppear |
@FocusState cannot co-animate with a presentation; worse, at bind time the field may not be mounted, so focus fails silently — no keyboard at all |
Any auto-focus on a .medium detent sheet |
The keyboard SHOVES the medium sheet to full height (Apple Forums #743274): the input bar travels sheet-distance + keyboard-height and settles back — the big ride |
| Retiring the prewarm field when you attempt the handoff | If focus didn't land yet, unmounting the prewarm resigns first responder and the keyboard drops mid-presentation |
The pattern (4 pieces, all required)
- UIKit prewarm field — a near-invisible
UITextFieldthat callsbecomeFirstResponder()indidMoveToWindow. UIKit can grab the keyboard during a presentation transition, so the keyboard rises with the sheet. (Pattern origin: github.com/naan/FocusOnAppear.) - Land-gated handoff — after the sheet content mounts (~400ms is safe; the keyboard is already visibly up so the wait is invisible), set the real field's
@FocusState. Retire the prewarm only when focus actually lands (onChange(of: focused)), never on the attempt. - Open at
.large— never auto-focus on a.mediumdetent. If the sheet has a detent-selection binding, reset it to.largefor the next open. - Freeze bottom accessories from frame one — anything that collapses when focus lands (emote strips, suggestion rows) must render collapsed from the first frame during auto-open, or its height change adds another bar jump mid-rise.