Navigatrix is a Ruby library for rendering custom navigation menus in Rails and Sinatra.
Navigation menu requirements rarely change – clicking a navigation menu link should cause the link to render in some sort of “active” state. For example, when visiting http://www.foraker.com/blog, the “Blog” link in the main navigation at the top of the page should be active.
Additionally, we’ll often need to manually activate a link. For example, when visiting the http://www.foraker.com/2013/04 blog archive path, the “Blog” link should appear active, even though the path does not contain
Navigatrix was designed to make rendering navigations, and activating and deactivating navigation items a breeze.
To install Navigatrix, add the Navigatrix gem to your Gemfile.
A simple navigation
Building a simple list-based navigation is trivial with Navigatrix. For example, this configuration:
renders the following HTML navigation, assuming we’re currently on the
The “Dashboard” nav item is not linked because we are currently on the
/home path, and the “Dashboard”
<li> receives a class of “active”.
This approach works well for simple navigations, and supports a variety of configuration options. Sometimes, though, a highly customized navigation requires a bolder solution.
Custom navigation requirements
I’ve no earthly idea why anyone would need to do this (perhaps to comply with a UI framework’s markup conventions), but suppose the desired navigation structure looks like this:
Let’s build this wild beast with Navigatrix.
There are a couple of Navigatrix design principles to explore before we embark on constructing a custom navigation.
1. Separation of configuration and rendering
Configuring a navigation and rendering a navigation are two distinct concerns. Changing the structure of our markup should not require a change to the navigation configuration, and likewise, changing the navigation configuration should not impact the markup.
To satisfy the custom navigation requirements above, our configuration will be:
With the default rendering behavior, we get a basic nested navigation.
Without altering the configuration of this navigation, we can radically alter the generated markup. But first let’s discuss a second design principle, lists vs. list items.
2. Lists are rendered independently of list items.
In a default Navigatrix navigation, a
<ul> represents a “list” of navigation items. Each “list item” is represented by an
Our custom navigation demands a
<div><table> wrapper to represent the list, and a
<tr> for each list item.
Here is the outer list component of our example:
And here is the outer list item:
Within each outer list item, there is yet another type of list, which we’ll call the nested “inner list.”
And inside the inner list, yet another type of list item.
Creating the outer list
The process of teaching Navigatrix new rendering strategies is known as “registering a renderer“, and we can control the rendering of lists and list items independently.
In order to achieve our custom UI goals, we’ll need to create 4 renderers, 1 renderer for each list type, and renderer 1 for each list item type. In Rails, registering new renderers is typically done in an
We can start by registering a renderer for the outer list called “table_list” in
And then, in the same initializer, register a renderer for the outer list item, called “table_item”.
Creating the inner list
Just as we registered a renderer for the outer list and outer list items, we can also register a renderer for the inner “nested list” and inner “nested list item”.
Rendering the list
Finally, we must specify which renderers to use in our call to
A brief word of caution: If your navigation needs fall too far afield of standard Navigatrix configuration, it might be time to consider rolling navigation yourself. Off-the-shelf solutions are certainly nice, but can become quite a headache when deviating from the library’s intended use.