Sinatra, SimpleNavigation and Bootstrap

After getting a handle on it, I was really surprised that Twitter’s excellent Bootstrap UI framework didn’t have functionality to cover tabs on other pages of the site. Much like the slick ScrollSpy, where various menu items are highlighted when you scroll to their div id on the page, I was expecting a “PageSpy” type functionality to do the same with navigation tabs, and set a tab to active if the target url matched the URL the browser was on (especially since bootstrap does the more difficult in-page tab functionality. In fact, I was so surprised, I actually asked around and took a look at the js source code as I thought I was missing something obvious.

So, I was stuck with coming up with a simple highlighting primary nav bar for my speedy little Sinatra app that integrated with Bootstrap. Looking around for simple tab gems that worked on more than Rails (tabulous is Rails-only, for example), the excellent simple-navigation gem popped out as being the simplest thing that would work (bar writing my own javascript).

A number of people have written custom renderers to get the old version of Bootstrap working directly with Subnavs and such, but if all your require is a primary nav bar using nav-tabs or nav-pills that’s overkill and you can shortcut all of this and use the basic setup below.

After putting gem 'simple-navigation'in your Gemfile and doing your bundle install you simply need to add the following in your main app.rb file (or similar). I use the modular style of building Sinatra apps which needs the register directive you see. If you’re going even simpler, you won’t need that.

require 'rubygems'
require 'sinatra/base'
require 'sinatra/simple-navigation'

class App < Sinatra::Base
register Sinatra::SimpleNavigation

# Application code starts here

Then it’s a simple matter of creating a file (and possibly new directory if you’re not using /config) navigation.rb

SimpleNavigation::Configuration.run do |navigation|
  # sets selected tab/pill to .active class that Bootstrap uses
  navigation.selected_class = 'active'
  # optional: an extra class simplnav applies changed for clarity       
  navigation.active_leaf_class = 'active-leaf'

  navigation.items do |primary|
    # sets the containing ul class="nav nav tab" for Bootstrap
    primary.dom_class = 'nav nav-tab'            
    # optional: id set to "", this changed for clarity
    primary.dom_id = 'nav-tabs'                  
    primary.item :projects, 'Projects', '/projects'
    primary.item :archives, 'Archives', '/archives'
    primary.item :about, 'About', '/about'
  end
end

Since my application dynamically sets all but the special pages (ie. like Archives), I just pass along the path URL to find the pages and SimpleNavigation takes care of the rest. Schmicko.

In the view (note: I’m using haml), I simply call the render_navigation helper now in my layout.rb.

%body
  .navbar.navbar-fixed-top
    .navbar-inner
      .container
        %a.brand{:href => "/"} Tundramonkey
        %a.btn.btn-navbar(data-toggle="collapse" data-target=".nav-collapse")
          %span.icon-bar
          %span.icon-bar
          %span.icon-bar
        .nav_collapse
          = render_navigation
  = yield

And that’s it. Seriously. Simple as the gem name implies and works with either nav-tabs or the nav-pills UI styles in Bootstrap.

The rest is simply styling up the default bootstrap css to your needs or using the default and pushing your multi-page app online.