Setup

#Installation

Add the gem to your Gemfile and run the install generator:

bundle add ruby_native
rails generate ruby_native:install

The generator creates config/ruby_native.yml and prints instructions for updating your layout.

#Tabs

Define your tab bar in config/ruby_native.yml with a title, path, and icon for each tab.

tabs:
  - title: Home
    path: /
    icon: house
  - title: Profile
    path: /profile
    icon: person

See the tabs guide for eager loading, tab routing, and the auto_route option.

#Entry path

By default the app launches on the first tab's path. Set entry_path to override this.

app:
  entry_path: /inbox

If entry_path is not set, the app loads the first tab's path, then falls back to /.

#Layout

Add native_tabs_tag to your layout <body> to tell the app when to show the tab bar. Like all Ruby Native helpers, it must render inside the <body>, not the <head>. See the tabs guide for React and Vue examples.

<%= native_tabs_tag if user_signed_in? %>

#Stylesheet

Include the gem's stylesheet in your layout <head>. This provides utility classes for safe area layout and hides elements marked with native-hidden.

<%= stylesheet_link_tag :ruby_native %>

On Sprockets apps, also add //= link ruby_native.css to app/assets/config/manifest.js or the tag raises an error. Propshaft apps need no extra step.

#Viewport meta tag

Add viewport-fit=cover to your viewport meta tag. This is required for CSS env(safe-area-inset-*) variables to return real values when the web view extends behind the status bar. Without it they resolve to 0 and the native-inset classes silently add no padding, so content hides under the status bar.

<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">

#Safe area layout

The web view extends behind the status bar and Dynamic Island. Add the native-inset class to your main content wrapper so content clears the status bar at the top and the tab bar at the bottom. It stacks with your existing padding.

<main class="px-4 pb-8 native-inset">
  <%= yield %>
</main>

Use native-inset-top or native-inset-bottom if you only need one side. See the appearance guide for details and fixed navbar handling.

#Hide web-only UI

Use native_app? to hide elements that the native app replaces, like a web navbar or footer.

<%= render "navbar" unless native_app? %>
<%= render "footer" unless native_app? %>

#Check the native library version

Use native_version to show or hide content based on the Ruby Native library version the app was built with, like a feature that needs a newer native shell. It returns "0" when the version is unknown and supports string comparisons. For the app's own version, use native_app_version below.

<% if native_version >= "0.13" %>
  <%# Show features that require the 0.13 native shell %>
<% end %>

#Read app and device details

Four more helpers expose what the app reports about itself and the device. Each returns a string for native requests and nil for web browsers.

<%= native_app_version %> <%# "5.2", the app's marketing version %>
<%= native_app_build %>   <%# "35", the build number %>
<%= native_os_version %>  <%# "26.5.2", the iOS or Android version %>
<%= native_os_build %>    <%# "23F79", the OS build number %>

native_app_build, native_os_version, and native_os_build also return nil for app builds from before the User-Agent carried them.

#Next steps

  • Tabs - eager loading, tab routing, and the auto_route option
  • Navigation bar - add a native navbar with buttons and menus
  • Appearance - customize colors, dark mode, and edge-to-edge content
  • Inertia (React & Vue) - setup for apps using React or Vue instead of ERB