Advanced Mode (BETA)

Advanced Mode replaces web navigation with native screen transitions. Pages push and pop with the same animations users expect from any native app, complete with a native navigation bar, back button, and swipe-to-go-back gesture. It builds on Normal Mode, so everything you already have keeps working.

Please note that Advanced Mode is currently in BETA. There might be some rough edges or bugs and the API might change. If you run into any issues then please email joe.

What you get

  • Native screen transitions with push/pop animations and swipe-to-go-back
  • Native navigation bar with a system back button
  • Submit buttons in the navigation bar that disable during form submission
  • Navigation bar buttons with SF Symbol icons (e.g., a "+" button to create a new record)
  • Action sheet menus triggered from the navigation bar (e.g., edit, delete)
  • Search bars that dispatch query events as the user types

Going Advanced means hiding your web navbar and letting the native navigation bar handle those actions instead.

Setup

  1. Set your app mode to advanced in config/ruby_native.yml:
app:
  mode: advanced
  1. Install the JavaScript dependency:
yarn add @hotwired/hotwire-native-bridge
# or
bin/importmap pin @hotwired/hotwire-native-bridge
  1. Import the controllers in your JavaScript entrypoint:
import "ruby_native/bridge"
  1. Hide your web navbar for native users:
<%= render "navbar" unless native_app? %>

Tabs

Shows or hides the native tab bar. Use native_tabs_tag in your layout:

<%= native_tabs_tag(enabled: user_signed_in?) %>

Form

Adds a native submit button in the navigation bar. The button disables automatically during form submission and re-enables when done.

Use native_form_data and native_submit_data:

<%= form_with model: @link, data: native_form_data do |f| %>
  <%= f.text_field :url %>
  <%= f.submit "Save", data: native_submit_data %>
<% end %>

The native button's title comes from the submit element's bridge-title attribute (or its text content). Tapping the native button clicks the web submit button under the hood. The web submit button is automatically hidden when the native button is active (via the gem's stylesheet).

Button

Adds a native button to the navigation bar. When tapped, it clicks the web element. Use the native_button_tag helper:

<%= native_button_tag "Add a link", new_link_path, ios_image: "plus", class: "btn btn-primary" %>

Options:

  • ios_image: sets the SF Symbol icon (e.g., "plus", "square.and.pencil"). Falls back to the title text if not provided.
  • side: sets the placement in the navigation bar. Defaults to :right. Use :left to place it next to the back button.
  • Any additional HTML options (like class:) are passed through to the underlying link_to.

You can have both a left and right button on the same page. The left button supplements the back button rather than replacing it.

The web element is automatically hidden when the native button is active (via the gem's stylesheet).

Push notifications

Requests push notification permission from the user. Use native_push_tag:

<%= native_push_tag %>

Place this on any page where you want to prompt for push permissions.

Menu

Displays a native action sheet with menu items. Use the native_menu_tag helper:

<%= native_menu_tag(title: "Actions") do |menu| %>
  <%= menu.item "Edit", edit_link_path(@link) %>
  <%= menu.item "Delete", link_path(@link), method: :delete, destructive: true %>
<% end %>

Options on native_menu_tag:

  • title: sets the action sheet title.
  • side: sets the placement of the ellipsis button. Defaults to :right.

Options on menu.item:

  • method: sets the Turbo method (e.g., :delete).
  • destructive: true styles the item in red.

The menu element is hidden by default (inline display:none). It has no web representation. The native app shows its own action sheet when connected.

Search

Adds a native search bar to the navigation bar. Use native_search_tag:

<%= native_search_tag %>

Dispatches a bridge--search:queried Stimulus event with the search query as the user types. Listen for it in your results controller:

// results_controller.js
search({ detail: { query } }) {
  // Filter or fetch results based on query
}

The native search bar replaces the need for a web-based search input on pages where this controller is connected.

Migrating from Normal to Advanced

If your app already uses Normal Mode, adding Advanced features is straightforward:

  1. Set mode: advanced in your config/ruby_native.yml (see setup above).
  2. Install the JavaScript dependency and import ruby_native/bridge.
  3. Hide your web navbar with native_app? so the native navigation bar takes over.
  4. Start using Advanced helpers (native_button_tag, native_menu_tag, native_form_data/native_submit_data, native_search_tag) on individual pages.

You can migrate one page at a time. Normal helpers like native_tabs_tag, native_push_tag, and native_form_tag keep working alongside Advanced helpers.