Breadcrumb Navigation

Part 25 of building a Rails 7 application

In the previous blog I wrote about designing the user interface for nesting related information under a parent record. One thing that is missing from that is there is a disconnect for the user as to where they are in that nesting when switching between tabs.

One way to resolve this issue is by showing a set of "breadcrumbs" that give a visual indication of which parent record they are looking at when viewing the related information. These breadcrumbs can also act as navigation to other parts of the application.

Here is what the end result will look like:

image.png

The user knows they are looking at a specific "Item Sell Pack" called "bag". They can click "Item Sell Packs" to navigate back to the list to choose another one, or they can click on the "Home" icon to return to the home page for the application.

To make this happen is pretty easy, I can add a BreadcrumbNavigation ViewComponent like so:

app/components/breadcrumb_navigation/component.rb

module BreadcrumbNavigation
  class Component < ViewComponent::Base
    include Turbo::StreamsHelper

    renders_many :breadcrumbs, Breadcrumb::Component

    attr_accessor :id

    def initialize(id:)
      super
      @id = id
    end
  end
end

And this will render many Breadcrumb components.

app/components/breadcrumb/component.rb

module Breadcrumb
  class Component < ViewComponent::Base
    attr_accessor :id, :label, :url, :active

    def initialize(id:, label:, url:, active: false)
      super
      @id = id
      @label = label
      @url = url
      @active = active
    end

    def active_classes
      active ? 'font-bold text-sky-500 hover:text-sky-700' : 'font-medium text-gray-500 hover:text-gray-700'
    end
  end
end

Anywhere that needs breadcrumb navigation simply renders the component into the view. For example, in the previous blog there were Item Sell Pack Aliases underneath an Item Sell Pack.

app/views/item_sell_pack_aliases/index.html.erb

<%= render BreadcrumbNavigation::Component.new(id: dom_id(@parent)) do |component| %>
  <% component.with_breadcrumb(id: :item_sell_packs, label: 'Item Sell Packs', url: item_sell_packs_url) %>
  <% component.with_breadcrumb(id: dom_id(@parent), label: @parent.to_s, url: item_sell_pack_path(@parent), active: true) %>
<% end %>