The root of a tabbed app: a floating tab bar, a stack per tab and real reselect behaviour.
An app shell on the lens tab bar in a bottom safe-area inset, generic per-tab content, hide-on-scroll through ShellScrollView, and reselect that pops to root and scrolls to top.
$199 once, every piece included. See how installing works · Sign in
SwiftUI source you own, built on Apple frameworks only.
NavigationStack per tab on the Lens Tab BarShellScrollViewLessons. Installed together, automatically.
Swift Pieces Skill (setup), Native (style), Onboarding to Paywall (recipe). Your agent builds around this screen in the same design.
Subscription App (template), Finance App (template), AI Assistant (template), Productivity App (template), Meditation App (template), Travel App (template)
How it behaves, what it handles, and the decisions behind it.
One NavigationStack per tab, the system tab bar hidden, and LensTabBar placed in .safeAreaInset(edge: .bottom) so scrolling content is never covered. Wrap each tab's scrolling content in ShellScrollView: it reports its offset to the shell, which hides the bar on a downward scroll and shows it again on an upward one or near the top. Reselecting a tab pops its stack to root and scrolls the root to the top.
(LensTab) -> Content closure, with no AnyView.ShellScrollView uses ScrollPosition and onScrollGeometryChange on iOS 18, and ScrollViewReader with a geometry probe on iOS 17. Scroll offsets travel up through a preference and the scroll-to-top token travels down through the environment, so the scroll container can live anywhere in the tab, including pushed screens.List does not report offsets; use ShellScrollView with a LazyVStack for rows.LensTabBar from the Lessons screen; the CLI installs it with this screen.TabShellScreenExample at the end of TabShellScreen.swift is the screen shown in the preview; copy it as a starting point.SPTheme tokens from @Environment(\.spTheme) and requires the design-system item.color.accent to LensTabBar as its tint, spaces the bar with space.sm, and scrolls to top with motion.smooth.@Environment(\.spTheme) in your screens so they match the bar.LensTabBar stays self-contained: its unselected icons, material fallback and springs use system values.Pieces that work well next to this one.