Tabs and sidebar
Declare tab stacks, search and action bubbles, adaptive sidebars, badges, and accessories.
A tab shell gives every main destination its own navigation stack:
Theme.NavigationTitleStyle sets the default for pages in every navigation stack. A page with a null NavigationTitleStyle follows it; TitleStyle.Inline and TitleStyle.Large override it for that page. The running value can be changed through SkeleApplication.Current.Theme.NavigationTitleStyle.
Tab, group, and bubble icons accept local ImageSource values. A plain string tries an SF Symbol first and then a bundle asset, so the concise calls above remain valid; use ImageSource.Bundle(...) when the source must be explicit. The title is also the identifier used by INavigator.SelectTabAsync.
Every destination declares its placement where it is added. Tab<TView>(), Split(...), and Group(...) all accept a TabPlacement argument.
A tab can be a split view instead of a single stack:
The other tabs keep their single-stack behavior. A split view can't be nested inside a group.
Search<TView>() creates the system search destination. On iOS 18 it appears as a normal tab; on iOS 26 it uses the separated search presentation. Bubble<TView>() uses that separated position for another destination on iOS 26 and falls back to a normal tab on iOS 18. Bubble(title, icon, action) creates an action instead, and the ViewModel overload resolves an ICommand from dependency injection and accepts an optional command parameter. Its iOS 18 fallback looks like a normal tab but runs the action without changing the selected page. Search and Bubble are mutually exclusive.
Adaptive sidebar
Sidebar enables the native adaptive tab/sidebar presentation:
Compact environments keep the bottom tab bar. iPad and supported iOS 27 environments use the sidebar; UIKit changes placement without SkeleKit rebuilding the destinations, so their navigation and view state survive resizing.
Automatic, Default, Optional, Movable, Pinned, Fixed, and SidebarOnly mirror UIKit's placement options. Hidden is SkeleKit's programmatic-only placement: those destinations never appear in the tab bar or sidebar and are selected with INavigator.SelectTabAsync.
SidebarOnly destinations are created once on every device but are visible only while a sidebar is available. They therefore have no visible entry in an iPhone bottom tab bar. Calling Sidebar() is required when declaring a sidebar-only destination or group. Groups belong to the tab hierarchy, default to SidebarOnly, and can be nested.
The Sidebar callback configures the sidebar itself rather than declaring destinations. Omit it when no sidebar-specific configuration is needed:
Badges and reselection
Set ContentView.TabBadge to a string or binding. Assign null to clear it. TabBadgeColor replaces the system red background. A root page can update its badge even before the tab has been opened.
TabReselectedCommand replaces the default pop-to-root or scroll-to-top behavior for an already-selected tab.
The badge and reselection properties belong to ContentView; page chrome and toolbars covers the rest of the page-owned shell configuration.
iOS 26 additions
Search and Bubble adopt the separated trailing presentation on iOS 26. Their normal-tab fallbacks keep the same destinations and actions available on iOS 18.
Theme.TabBarMinimize allows the tab bar to minimize while scrolling. The running value is available through SkeleApplication.Current.Theme.TabBarMinimize.
Accessory<TView>() hosts an app-level view above the tab bar; the view's IsVisible controls whether the slot is shown. Sidebar(sidebar => sidebar.Footer<TView>()) fills the sidebar footer. Both accessory slots are ignored before iOS 26.