How to Switch Tabs from Links in Hotwire Native

Hotwire Native doesn't switch tabs for you. Click "See all Posts" from your Home tab and you'll push a new view onto Home's navigation stack. The Posts tab sits there, untouched. Your users will hate this.

I ran into this building both PrayAI and Fitivity. Both apps have tab bars. Both needed links that feel native—tap a link, land on the right tab. The solution is path configuration, and it's cleaner than you'd expect.

The Problem


Hotwire Native's navigator handles routing. It sees a URL, matches it against your path configuration, and pushes or presents accordingly. But it doesn't know anything about your tab bar. That's UIKit territory, and Hotwire stays out of it.

So when a user taps "View all meditations" from the Home tab, Hotwire pushes the meditations list onto Home. Now you've got meditations content living under the wrong tab. The user taps the Meditations tab expecting to see their list—nothing. They tap back on Home and there it is. Confusing.

The Solution: Path Configuration Properties


Path configuration isn't just for modals and presentation styles. You can add any property you want. I use tab_identifier to tell my navigator which tab owns a given path.

Add it to your path configuration JSON:

{
  "settings": {},
  "rules": [
    {
      "patterns": ["/meditations", "/meditations/*"],
      "properties": {
        "tab_identifier": "meditations"
      }
    },
    {
      "patterns": ["/posts", "/posts/*"],
      "properties": {
        "tab_identifier": "posts"
      }
    }
  ]
}

Now your navigator knows which tab each path belongs to. You just need to act on it.

Handle It in Your Navigator Delegate


In your NavigatorDelegate, check for the tab identifier before accepting the route:

func handle(proposal: VisitProposal) -> ProposalResult {
    let properties = proposal.properties
    
    if let tabIdentifier = properties["tab_identifier"] as? String {
        switchToTab(identifier: tabIdentifier)
    }
    
    return .accept
}

The switchToTab function finds the right tab and selects it:

func switchToTab(identifier: String) {
    guard let tabBarController = window?.rootViewController as? UITabBarController else { return }
    
    let tabMap = ["home": 0, "meditations": 1, "posts": 2, "profile": 3]
    
    if let index = tabMap[identifier] {
        tabBarController.selectedIndex = index
    }
}

That's it. Now when someone taps "See all Posts" from anywhere in your app, they land on the Posts tab with the posts list. Native behavior. No weird navigation stack pollution.

Why This Works


Path configuration is your single source of truth for routing behavior. Adding tab ownership there keeps everything in one place. Your native code stays thin—just a lookup and a tab switch.

You could hard-code this logic in Swift, checking URLs and mapping them to tabs. But then you're maintaining routing rules in two places. Path configuration already exists. Use it.

The pattern scales too. Need certain links to open in Safari? Add a property. Need some paths to require authentication? Property. Hotwire Native gives you the hooks. You decide what to do with them.

Ship It


Tab switching isn't built into Hotwire Native because tab bars aren't universal. Some apps don't have them. Some have different navigation patterns entirely. But if you're building a standard tabbed iOS app, this pattern takes fifteen minutes to implement and makes your app feel right.

Start with your most common cross-tab links. Add the path configuration rules. Wire up the delegate. Your users will never notice—and that's exactly the point.