Skip to main content
Spree Admin Dashboard provides a flexible navigation system that allows you to easily extend the sidebar navigation with your own menu items without modifying the core codebase. This enables safe updates while maintaining your customizations.
Starting with Spree 5.2, the navigation system uses a declarative API accessible via Spree.admin.navigation. This allows you to programmatically add, modify, and remove navigation items directly in your initializers.

Basic Usage

Add navigation items in your config/initializers/spree.rb file:
config/initializers/spree.rb

Available Options

All navigation items support the following options:
label
Symbol or String
required
The text label for the navigation item. Can be a symbol (translation key using Spree.t) or a string.
url
Symbol or Lambda
required
The URL for the navigation item. Can be a route helper symbol (:admin_brands_path) or a lambda returning a URL.
icon
String
Icon name from Tabler Icons.
position
Integer
default:"0"
Numeric position in the menu. Lower numbers appear first.
active
Lambda
Lambda to determine if the link should be highlighted as active. Receives view context.
if
Lambda
Conditional display logic. The item only appears if this lambda returns true. Has access to view context helpers like can?, current_store, etc.
badge
String or Lambda
Badge text/count to display next to the label. Can be a string or lambda that returns a value.
badge_class
String
CSS class for badge styling (e.g., 'badge-info', 'badge-warning').
tooltip
String
Tooltip text shown on hover.
target
String
Link target attribute (e.g., '_blank' to open in a new tab).
section_label
String
Creates a section divider with the given label instead of a clickable link.
parent
Symbol
The key of an existing navigation item to nest this item under. This is the simplest way to add items to existing submenus.
The navigation system supports multiple contexts. Spree provides predefined contexts for common use cases, and you can register custom contexts for your specific needs. The main sidebar navigation:

Settings Navigation

Navigation in the Settings area:

Page Tab Navigation

Spree provides several predefined tab contexts for common admin pages:

Registering Contexts

Use register_context to create a new navigation context:
name
Symbol or String
required
The unique name for the navigation context. Will be converted to a symbol internally.
Returns: Spree::Admin::Navigation - The navigation context instance Note: Calling register_context multiple times with the same name returns the same instance (idempotent).

Custom Tab Contexts

You can create custom tab contexts for your own admin pages using register_context:
config/initializers/spree.rb
Then render the tabs in your view using the render_tab_navigation helper:
app/views/spree/admin/brands/index.html.erb
Always register custom contexts in your initializer before accessing them. Attempting to access an unregistered context will raise a NoMethodError.

Listing All Contexts

You can list all registered navigation contexts:

Checking If a Context Exists

Creating Submenus

Add a parent item, then add child items using the parent option:
config/initializers/spree.rb
Parent items are automatically marked as active when any of their children are active. You don’t need to manually define the active option for parent items.

Modifying Existing Navigation

Finding Navigation Items

Adding to Existing Submenus

Use the parent option to add an item to an existing submenu:

Removing Navigation Items

Updating Navigation Items

Replacing Navigation Items

Moving Navigation Items

Advanced Examples

Section Dividers

Dynamic URLs

Complex Conditional Display

Complex Active State Logic

Best Practices

Authorization

Always use if: -> { can?(...) } to ensure users only see navigation items they have permission to access.

Translations

Use symbols for labels (e.g., label: :brands) to support internationalization via Spree.t.

Active States

Define clear active state logic using lambdas to highlight the current section properly.

Positioning

Use consistent position intervals (e.g., 10, 20, 30) to leave room for future additions.

Common Positioning Reference

Main sidebar navigation positions:
  • Getting Started: 5
  • Home: 10
  • Orders: 20
  • Returns: 25
  • Products: 30
  • Customers: 40
  • Promotions: 50
  • Reports: 60
  • Storefront: 70
  • Integrations: 80
  • Settings Section: 90
  • Settings: 100
  • Admin Users: 110

Troubleshooting

  • Ensure active: lambda returns true/false
  • Check that controller_name or other conditions match correctly
  • For submenus, ensure parent uses same active logic as children
  • Ensure the badge lambda returns a non-nil value
  • Check that the badge value is truthy (empty strings won’t display)
  • For numeric badges, ensure the count is greater than 0

Previous versions

The following documentation applies to Spree 5.1 and earlier. If you’re using Spree 5.2+, please refer to the documentation above.

How it works

The admin navigation system works through injection points defined throughout the sidebar. You can inject custom navigation items into these predefined locations, add new top-level menu items, or create nested submenus. The main navigation file is located at admin/app/views/spree/admin/shared/sidebar/_store_nav.html.erb and provides several injection points:

Available Injection Points

store_nav_partialsInjects navigation items into the main sidebar navigation, after the Reports item and before the Storefront and Integrations sections.
Main navigation injection point
This is the primary injection point for adding custom top-level navigation items.
store_products_nav_partialsInjects navigation items into the Products submenu, after the Properties item.Use this to add product-related navigation items that logically belong under the Products section.
store_orders_nav_partialsInjects navigation items into the Orders submenu, after the Draft Orders item.Use this to add order-related navigation items.
store_settings_nav_partialsInjects navigation items into the Settings section, after the Policies item.Use this when Settings mode is active to add configuration-related items.
settings_nav_partialsInjects navigation items at the end of the Settings section.Use this to add additional settings-related navigation items.

Using the nav_item Helper

The nav_item helper method is provided by Spree::Admin::NavigationHelper and makes it easy to create properly formatted navigation items.

Method Signature

Parameters

label
String
The text label for the navigation item. Can be HTML-safe content.
url
String
The URL the navigation item links to. Use the spree. route helper prefix.
icon
String
default:"nil"
Optional icon name from Tabler Icons. The icon will be displayed before the label.
active
Boolean
default:"nil"
Manually set whether the link should be marked as active. If not specified, it will be auto-detected based on the current URL.
data
Hash
default:"{}"
Additional data attributes to add to the link element.

Basic Usage

With Active State

With Block Content

Adding a Simple Navigation Item

Let’s add a new “Inventory” navigation item to the main sidebar.

Step 1: Create the Partial

Step 2: Add Navigation Code

app/views/spree/admin/shared/_inventory_nav.html.erb
Always wrap your navigation items with authorization checks using can?() to ensure users only see menu items they have permission to access.

Step 3: Register the Partial

Add this to your config/initializers/spree.rb:
config/initializers/spree.rb

Step 4: Add Translations

In your config/locales/en.yml:
config/locales/en.yml

Step 5: Restart Your Server

Restart your web server to load the initializer changes. The navigation item should now appear in the sidebar.

Creating Nested Navigation (Submenus)

To create a navigation item with a submenu, you need to use the nav-submenu class and manage the visibility based on the active state.

Example: Adding a Nested Menu

Key Points for Submenus

  1. Active State Variable: Define a variable to track when any item in the menu group is active:
  2. Parent Navigation Item: Use the active state variable for the parent item:
  3. Submenu Container: Use the nav-submenu class and conditionally add d-none to hide when inactive:
  4. Child Items: Add child navigation items within the submenu:
  5. Nested Injection Point (Optional): Add an injection point within the submenu for further extensibility:

Advanced Examples

Extending Existing Submenus

To add an item to an existing submenu (e.g., Products), use the appropriate injection point: Create: app/views/spree/admin/shared/_custom_products_nav.html.erb
Register in config/initializers/spree.rb:
config/initializers/spree.rb
When the admin is in “Settings mode” (the dedicated settings view), use the settings_nav_partials injection point:
Register with:
config/initializers/spree.rb

Best Practices

Authorization

Always use can?() checks to ensure users only see navigation items they have permission to access.

Translations

Use Spree.t() for all navigation labels to support internationalization.

Icons

Use consistent icons from Tabler Icons that match Spree’s design language.

Active States

Define clear active state logic to highlight the current section in the navigation.

Route Helpers

Always use spree. prefixed route helpers to reference admin routes correctly.

Injection Points

Add your own injection points in submenus to allow further extensions by other developers.

Common Patterns

Multiple Controller Check

Path-based Check

Controller and Action Check

Parameters-based Check

Troubleshooting

  • Verify the icon name exists in Tabler Icons
  • Check that you’re using the correct parameter name: icon: not icon_name:
  • Ensure the icon name is a string, e.g., icon: 'boxes'
  • Add the translation key to your locale file
  • Ensure the locale file is in the correct location
  • Restart your server after adding translations
  • Check for typos in the translation key