Pattern · Tab Bars
NewAccessory Tab Bar SwiftUI Block
A tab bar with a live accessory above it for what is playing or running, folding inline into the bar as the content scrolls.
A compact accessory above the tab bar shows what is live: artwork, title and subtitle, a progress line and play and pause or one control of your own, opening its full view when tapped. Scrolling down folds it inline into the bar beside the selected tab, and scrolling up brings it back. On iOS 26 it is the system bar's tabViewBottomAccessory, with the block's own bar before.
- SwiftUI
- iOS 17.0+
- accessory-tab-bar
$199 once, every piece included. See how installing works · Sign in
01
What's included
SwiftUI source you own, built on Apple frameworks only.
- A live accessory row with artwork, progress and one control
- Folds inline into the bar on scroll down and returns on scroll up
- The system tabViewBottomAccessory on iOS 26, a matching custom bar on iOS 17
- Play and pause, or your own control, with working and failed states
- Tap the accessory to open its full view through your closure
02
Implementation notes
How it behaves, what it handles, and the decisions behind it.
A compact accessory sits just above the tab bar for whatever is live: the episode playing, the workout running, the order on its way. It shows an artwork square, a title and subtitle, a thin progress line and one control, play and pause by default; tap the row to open its full view through your closure. The control runs your closure and shows a spinner while it does, and a thrown error replaces the subtitle for a few seconds. As the content scrolls down the bar steps aside: the tab capsule shrinks to a round button showing the selected tab, and the accessory folds down beside it, with its title and control. Scrolling back up, or tapping that symbol, brings the tabs and the full accessory back. On iOS 26 the block is the system TabView with tabViewBottomAccessory and tabBarMinimizeBehavior(.onScrollDown), in Liquid Glass; before iOS 26 it draws its own bar in the same shape: the tabs in a floating capsule, the selected one on a quiet pill, with the accessory in a capsule above.
Notes
AccessoryTabBar(selection:items:accessory:style:onControl:onExpand:content:)is generic over your own tab type.contentbuilds each tab's screen;accessoryis nil when nothing is live, and the accessory goes.- A tab bar is the root of a screen, so this block owns its container rather than being a section: it lays your content out full size and floats the bar over its foot, on a soft fade of the background. Put a
NavigationStackinside each tab. style: .automaticuses the system bar and accessory on iOS 26 and the block's own before;.customdraws the block's own on every version, so the look is the same everywhere.- The block's own bar learns about scrolling from content you mark with
.accessoryTabBarScrollTracking(), inside each tab'sScrollView. It folds after 40 points of scrolling down and returns after 40 points up, and always near the top. The system bar on iOS 26 watches scrolling itself, so the modifier does nothing there. AccessoryTabBarItem(_:title:symbol:badge:)(alsoAccessoryTabBar.Item) is a tab.AccessoryTabBarAccessory(alsoAccessoryTabBar.Accessory) has anid,title,subtitle, an SF Symbol for the artwork,progressfrom 0 to 1 (nil hides the line),isActiveand aControl:.playPause(Pause while active, Play otherwise),.action(symbol:label:)for one action of your own, such as ending a workout, or.none. Pass a new value as it changes..sampleis an episode playing,.workouta run with End workout,.ordera delivery with no control.onControlisasync throws: ask your player to pause or play, then updateisActive. A thrown error'serrorDescription(or "That didn't work. Try again.") shows in the subtitle in the danger colour for four seconds. Nil hides the control.onExpandopens your full view: a player sheet, the workout or the order.- VoiceOver reads the accessory as one element: its title, subtitle, percentage and Playing or Paused, with a hint that it opens the full view; the control is labelled Pause, Play or your label. Tabs read their badges and the selected trait. The bar keeps its size up to xLarge text; at accessibility sizes the labels step aside and a long press shows the large content viewer.
- Reduce Motion turns the fold and the accessory's rise into fades, and the waveform symbol holds still.
AccessoryTabBarExampleat the end ofAccessoryTabBar.swiftis a listening app: Home, Library, Search and Downloads, an episode playing whose line creeps on, a play control that takes a moment, and a Now Playing sheet. Passcustom: trueto see the block's own bar on iOS 26.
Theming
- Reads
SPThemefrom@Environment(\.spTheme)and requires thedesign-systemitem. - The custom bar's capsule is
color.surfacewith aseparatorhairline and thee2shadow, and the selected tab's pill isfill. Labels are intype.captionat medium weight,textPrimarywhen selected andtextSecondaryotherwise. Badges aretextPrimarycapsules withsurfacefigures. - The accessory is a
surfacecapsule with aseparatorhairline and thee2elevation, since it floats over scrolling content. The artwork square isfillatradius.smwith its symbol intextSecondary. The title istype.subheadat medium weight, the subtitletype.footnoteintextSecondary, the controltextPrimary, and the progress linetextPrimaryon afilltrack. - Folded, the tab button is a
surfacecircle and the accessory keeps its capsule, its artwork smaller atradius.xs. Behind the bar the background fades in frombgat 0 to 90%. - On iOS 26 the system draws the bar and the accessory's glass; the tab tint is
textPrimary. - The fold moves with
motion.standard; controls cross-fade withmotion.snappy.
Requirements
- iOS 26 for the system bar and accessory. Earlier versions use the block's own.
03
Keep building
Pieces that work well next to this one.