3.5.0
Tab accessibility identifiers, and a Stinsen migration guide
Per-tab accessibility identifiers
Tab bar items can now carry a stable identifier, so UI tests and accessibility tools address a tab independently of its localized label:
tabCoordinator.setTabAccessibilityIdentifier("tab.home", for: .home)
tabCoordinator.setTabAccessibilityIdentifier(nil, for: .home) // clear
tabCoordinator.tabAccessibilityIdentifier(for: .home) // read back: String?- A plain
.accessibilityIdentifier()on the tab's label view never reaches the rendered tab bar item — only theTabContentmodifier does, which is what the framework applies internally. - Identifiers are usually static: set them once in the coordinator's
init. The setter resolves the initial tabs itself, so it works before the first render. - Like badges, the identifier participates in each tab's render identity, because
TabViewignores changes to an already-createdTab. - With a custom tab bar (
TabItems(tabs:, visibility: .hidden)), read the identifier back withtabAccessibilityIdentifier(for:)and apply it to your own button. Destination.accessibilityIdentifieris public and read-only, alongsidebadge.
Migrating from Stinsen
A new documentation article maps every Stinsen construct to its Scaffolding equivalent — route declarations, rendering, observation, push vs. modal, tabs, chaining, and deep linking — plus the cases with no direct counterpart, the platform-floor jump, and the name collisions to watch for while both packages are linked during an incremental migration.
Internal
- Dropped the pre-iOS-18
TabViewrendering path and the@available(iOS 18, macOS 15)annotations aroundTabRole. Both sat below the package's platform floor (iOS 18 / macOS 15 / tvOS 18 / watchOS 11) and were unreachable. - The tabs tutorial gains a step on identifying tabs, and the custom tab bar example now carries identifiers through to its own buttons.
Full Changelog: 3.4.0...3.5.0