<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>navigation Blog</title>
        <link>https://navigation.apexnative.dev/blog</link>
        <description>navigation Blog</description>
        <lastBuildDate>Fri, 16 Oct 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[Introducing @apexnative/navigation]]></title>
            <link>https://navigation.apexnative.dev/blog/introducing-navigation</link>
            <guid>https://navigation.apexnative.dev/blog/introducing-navigation</guid>
            <pubDate>Fri, 16 Oct 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Why we are building native navigation for React Native where the platform owns the navigation and React describes it, and what it looks like in an app.]]></description>
            <content:encoded><![CDATA[<p><code>@apexnative/navigation</code> gives a React Native app the navigation of the platform itself: the stacks, tabs, sheets,
split views and gestures of iOS, iPadOS and Android. You describe the screens and how they are arranged in
TypeScript; the native side shows them and reports back. This post is about why we built it this way, and where it
goes next.</p>
<div class="videos_TJle"><div class="row_SxI5"><figure class="device_eCcz"><div class="frame_UGN6"><video class="video_eJXQ" poster="/video/intro-hero-ios.jpg" autoplay="" muted="" loop="" playsinline="" preload="metadata"><source src="/video/intro-hero-ios.webm" type="video/webm"><source src="/video/intro-hero-ios.mp4" type="video/mp4"></video></div><figcaption class="label_RVGx">iOS</figcaption></figure><figure class="device_eCcz"><div class="frame_UGN6"><video class="video_eJXQ" poster="/video/intro-hero-android.jpg" autoplay="" muted="" loop="" playsinline="" preload="metadata"><source src="/video/intro-hero-android.webm" type="video/webm"><source src="/video/intro-hero-android.mp4" type="video/mp4"></video></div><figcaption class="label_RVGx">Android</figcaption></figure></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-platform-already-knows-how-to-navigate">The platform already knows how to navigate<a href="https://navigation.apexnative.dev/blog/introducing-navigation#the-platform-already-knows-how-to-navigate" class="hash-link" aria-label="Direct link to The platform already knows how to navigate" title="Direct link to The platform already knows how to navigate" translate="no">​</a></h2>
<p><code>UINavigationController</code>, <code>UITabBarController</code>, sheets with detents, <code>UISplitViewController</code>, the Android back stack
and the Material components hold years of decisions about gestures, accessibility, screen sizes, memory and
multitasking. A router that keeps its own model of the navigation has to mirror all of it in JavaScript and keep up
with every OS release.</p>
<p>We went the other way. The platform owns the navigation state; React describes it. When iOS 26 brought the Liquid
Glass tab bar and the minimized tab bar, an app with this library got them by setting an option, not by waiting for a
JavaScript reimplementation.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="describe-dont-command">Describe, don't command<a href="https://navigation.apexnative.dev/blog/introducing-navigation#describe-dont-command" class="hash-link" aria-label="Direct link to Describe, don't command" title="Direct link to Describe, don't command" translate="no">​</a></h2>
<p>Native navigation libraries for React Native have existed for years, and they work: commands with screen ids and JSON
layouts. Their weak spot is that every mistake shows up at run time, a wrong screen name, a missing prop, the id of a
screen that is gone.</p>
<p>So the API is typed end to end:</p>
<div class="cb language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F3E9D2;--prism-background-color:#101828"><div class="cb__head"><span class="cb__title">src/Navigation.ts</span><button type="button" class="cb__copy">Copy</button></div><div class="cb__body"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#F3E9D2;background-color:#101828"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F3E9D2"><span class="token keyword" style="color:#F4A261">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#B5A88C">{</span><span class="token plain"> createNavigation</span><span class="token punctuation" style="color:#B5A88C">,</span><span class="token plain"> Tab</span><span class="token punctuation" style="color:#B5A88C">,</span><span class="token plain"> Tabs </span><span class="token punctuation" style="color:#B5A88C">}</span><span class="token plain"> </span><span class="token keyword" style="color:#F4A261">from</span><span class="token plain"> </span><span class="token string" style="color:#7FE0C4">'@apexnative/navigation'</span><span class="token punctuation" style="color:#B5A88C">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F3E9D2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F3E9D2"><span class="token plain"></span><span class="token keyword" style="color:#F4A261">export</span><span class="token plain"> </span><span class="token keyword" style="color:#F4A261">const</span><span class="token plain"> Navigation </span><span class="token operator" style="color:#F4A261">=</span><span class="token plain"> </span><span class="token function" style="color:#E9B949">createNavigation</span><span class="token punctuation" style="color:#B5A88C">(</span><span class="token punctuation" style="color:#B5A88C">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F3E9D2"><span class="token plain">  screens</span><span class="token operator" style="color:#F4A261">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#B5A88C">{</span><span class="token plain"> Home</span><span class="token operator" style="color:#F4A261">:</span><span class="token plain"> HomeScreen</span><span class="token punctuation" style="color:#B5A88C">,</span><span class="token plain"> Inbox</span><span class="token operator" style="color:#F4A261">:</span><span class="token plain"> InboxScreen</span><span class="token punctuation" style="color:#B5A88C">,</span><span class="token plain"> Chat</span><span class="token operator" style="color:#F4A261">:</span><span class="token plain"> ChatScreen </span><span class="token punctuation" style="color:#B5A88C">}</span><span class="token punctuation" style="color:#B5A88C">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F3E9D2"><span class="token plain">  root</span><span class="token operator" style="color:#F4A261">:</span><span class="token plain"> </span><span class="token function" style="color:#E9B949">Tabs</span><span class="token punctuation" style="color:#B5A88C">(</span><span class="token function" style="color:#E9B949">Tab</span><span class="token punctuation" style="color:#B5A88C">(</span><span class="token string" style="color:#7FE0C4">'Home'</span><span class="token punctuation" style="color:#B5A88C">)</span><span class="token punctuation" style="color:#B5A88C">,</span><span class="token plain"> </span><span class="token function" style="color:#E9B949">Tab</span><span class="token punctuation" style="color:#B5A88C">(</span><span class="token string" style="color:#7FE0C4">'Inbox'</span><span class="token punctuation" style="color:#B5A88C">)</span><span class="token punctuation" style="color:#B5A88C">)</span><span class="token punctuation" style="color:#B5A88C">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F3E9D2"><span class="token plain"></span><span class="token punctuation" style="color:#B5A88C">}</span><span class="token punctuation" style="color:#B5A88C">)</span><span class="token punctuation" style="color:#B5A88C">;</span><br></div></code></pre></div></div>
<div class="cb language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F3E9D2;--prism-background-color:#101828"><div class="cb__body"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#F3E9D2;background-color:#101828"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F3E9D2"><span class="token keyword" style="color:#F4A261">const</span><span class="token plain"> navigation </span><span class="token operator" style="color:#F4A261">=</span><span class="token plain"> </span><span class="token function" style="color:#E9B949">useNavigation</span><span class="token punctuation" style="color:#B5A88C">(</span><span class="token punctuation" style="color:#B5A88C">)</span><span class="token punctuation" style="color:#B5A88C">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F3E9D2"><span class="token plain">navigation</span><span class="token punctuation" style="color:#B5A88C">.</span><span class="token method function property-access" style="color:#E9B949">push</span><span class="token punctuation" style="color:#B5A88C">(</span><span class="token string" style="color:#7FE0C4">'Chat'</span><span class="token punctuation" style="color:#B5A88C">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#B5A88C">{</span><span class="token plain"> props</span><span class="token operator" style="color:#F4A261">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#B5A88C">{</span><span class="token plain"> chatId</span><span class="token operator" style="color:#F4A261">:</span><span class="token plain"> </span><span class="token string" style="color:#7FE0C4">'42'</span><span class="token plain"> </span><span class="token punctuation" style="color:#B5A88C">}</span><span class="token plain"> </span><span class="token punctuation" style="color:#B5A88C">}</span><span class="token punctuation" style="color:#B5A88C">)</span><span class="token punctuation" style="color:#B5A88C">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F3E9D2"><span class="token plain"></span><span class="token comment" style="color:#8C9AB5;font-style:italic">// 'Chats', or a missing chatId: a TypeScript error</span><br></div></code></pre></div></div>
<p>The screen names, the props of each screen and the roots the app switches between are checked by TypeScript.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="logic-outside-the-render-tree">Logic outside the render tree<a href="https://navigation.apexnative.dev/blog/introducing-navigation#logic-outside-the-render-tree" class="hash-link" aria-label="Direct link to Logic outside the render tree" title="Direct link to Logic outside the render tree" translate="no">​</a></h2>
<p>In a React app everything tends to end up in one tree: the socket, the session, the services, each in a provider,
each with re-render care. Here the app's life cycle is explicit. <code>willMount</code> runs while the splash screen shows and
decides the first screen, <code>didMount</code> runs once it is shown, <code>navigation</code> works from anywhere (a notification
handler, a link route, a store), and the app's context carries data and services every screen reads.</p>
<p>By default each screen is a React root of its own, which keeps screens independent. When you want one tree, for a
store or a query client, <code>appProvider</code> renders every screen inside it. Both are covered in
<a class="" href="https://navigation.apexnative.dev/docs/guides/state-management">State management</a> and <a class="" href="https://navigation.apexnative.dev/docs/guides/app-context">The app context</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="native-screens-are-first-class">Native screens are first-class<a href="https://navigation.apexnative.dev/blog/introducing-navigation#native-screens-are-first-class" class="hash-link" aria-label="Direct link to Native screens are first-class" title="Direct link to Native screens are first-class" translate="no">​</a></h2>
<p>A SwiftUI, UIKit or Jetpack Compose screen sits next to React screens: pushed, presented and typed the same way, set
up by the CLI. Teams adding React Native to a native app, or keeping a few screens native for performance, don't need
a second navigation.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="where-it-is">Where it is<a href="https://navigation.apexnative.dev/blog/introducing-navigation#where-it-is" class="hash-link" aria-label="Direct link to Where it is" title="Direct link to Where it is" translate="no">​</a></h2>
<p>The library is in early development. It is not on npm yet, and the API can still change before 1.0. The docs are
written ahead of the release, so you can read how everything works today:</p>
<ul>
<li class=""><a class="" href="https://navigation.apexnative.dev/docs/start/quick-start">Quick start</a>: an app with a stack in a few minutes.</li>
<li class=""><a class="" href="https://navigation.apexnative.dev/docs/guides/overview">Guides</a>: state, data fetching, gestures, deep links, notifications, testing.</li>
<li class=""><a class="" href="https://navigation.apexnative.dev/docs/migration/from-react-navigation">From React Navigation</a>: the same app, piece by piece.</li>
</ul>
<p>Feedback is welcome on <a href="https://github.com/apexnative/navigation/issues" target="_blank" rel="noopener noreferrer" class="">GitHub</a>.</p>]]></content:encoded>
            <category>announcement</category>
        </item>
    </channel>
</rss>