Configure Navigation Layout

Choose between sidebar and header navigation layouts, configure collapsed states, and customize the navigation experience for your SaaS application.

Makerkit offers two navigation layouts: sidebar (default) and header. A single navigation configuration serves both personal and team accounts — the active account is resolved from the database, so there is no per-account-type layout setting. All layout options are controlled through environment variables.

Quick Configuration

Set your preferred layout in .env.local:

# App navigation layout (serves personal + team accounts)
VITE_USER_NAVIGATION_STYLE=sidebar

Available values: sidebar, header, or custom.

Layout Options Compared

The sidebar layout places navigation on the left side of the screen, providing a persistent, vertically-oriented menu.

Click to expand

Best for:

  • Apps with many navigation items (5+)
  • Complex feature sets needing categorized menus
  • Desktop-first applications
  • Enterprise or admin-heavy dashboards

Configuration:

VITE_USER_NAVIGATION_STYLE=sidebar

Header Layout

The header layout places navigation horizontally at the top of the screen, with a more compact, traditional web app feel.

Click to expand

Best for:

  • Apps with fewer navigation items (3-5)
  • Consumer-facing products
  • Mobile-first designs
  • Simple, focused applications

Configuration:

VITE_USER_NAVIGATION_STYLE=header

Default Collapsed State

Control whether the sidebar starts expanded or collapsed:

# Sidebar collapsed default state
VITE_HOME_SIDEBAR_COLLAPSED=false

Set to true to start with a collapsed icon-only sidebar. Users can still expand it manually.

Collapsible Style

Choose how the sidebar collapses and expands:

# Options: offcanvas, icon, none
VITE_SIDEBAR_COLLAPSIBLE_STYLE=offcanvas
StyleBehavior
offcanvasSidebar slides in/out as an overlay (mobile-friendly)
iconSidebar collapses to icons only, expanding on hover
noneSidebar cannot be collapsed

Show or hide the sidebar toggle button:

VITE_ENABLE_SIDEBAR_TRIGGER=true

Set to false if you want the sidebar to remain in its configured state without user control.

Complete Configuration Example

Here's a full example configuring the app navigation:

# App navigation: header layout
VITE_USER_NAVIGATION_STYLE=header
VITE_SIDEBAR_COLLAPSIBLE_STYLE=icon
VITE_ENABLE_SIDEBAR_TRIGGER=true
# Theme settings
VITE_DEFAULT_THEME_MODE=system
VITE_ENABLE_THEME_TOGGLE=true

Customizing Navigation Items

Navigation items are defined in configuration files, not environment variables:

SidebarConfiguration File
Main app (dashboard)apps/web/config/navigation.config.tsx
Settings sectionapps/web/src/components/settings/settings-navigation.tsx

Application Navigation

import { CreditCard, Home, User, Settings } from 'lucide-react';
import { NavigationConfigSchema } from '@kit/ui/navigation-schema';
import pathsConfig from '#/config/paths.config.ts';
const iconClasses = 'w-4';
const routes = [
{
label: 'common.routes.application',
children: [
{
label: 'common.routes.home',
path: pathsConfig.app.home,
Icon: <Home className={iconClasses} />,
highlightMatch: `${pathsConfig.app.home}$`,
},
],
},
{
label: 'common.routes.settings',
children: [
{
label: 'common.routes.profile',
path: pathsConfig.app.settings,
Icon: <User className={iconClasses} />,
},
{
label: 'common.routes.billing',
path: pathsConfig.app.settingsBilling,
Icon: <CreditCard className={iconClasses} />,
},
],
},
];
export const workspaceNavigationConfig = NavigationConfigSchema.parse({
routes,
style: import.meta.env.VITE_USER_NAVIGATION_STYLE,
sidebarCollapsed: import.meta.env.VITE_HOME_SIDEBAR_COLLAPSED,
sidebarCollapsedStyle: import.meta.env.VITE_SIDEBAR_COLLAPSIBLE_STYLE,
});

Adding a New Navigation Item

To add a custom page to the navigation:

import { BarChart3 } from 'lucide-react';
const routes = [
{
label: 'common.routes.application',
children: [
{
label: 'common.routes.home',
path: pathsConfig.app.home,
Icon: <Home className={iconClasses} />,
highlightMatch: `${pathsConfig.app.home}$`,
},
// Add your custom navigation item
{
label: 'common.routes.analytics',
path: '/dashboard/analytics',
Icon: <BarChart3 className={iconClasses} />,
},
],
},
// ... rest of routes
];

Remember to add the translation key to your locale files:

{
"routes": {
"analytics": "Analytics"
}
}

The NavigationConfigSchema supports these properties:

interface NavigationConfig {
routes: {
label: string; // Translation key for section header
collapsible?: boolean; // Allow section to collapse (default: false)
children: {
label: string; // Translation key for item
path: string; // Route path
Icon?: ReactNode; // Lucide icon component
highlightMatch?: string; // Regex pattern for active route highlighting
}[];
}[];
style?: 'sidebar' | 'header' | 'custom';
sidebarCollapsed?: boolean | string;
sidebarCollapsedStyle?: 'offcanvas' | 'icon' | 'none';
}

Environment Variables Reference

VariableDefaultOptionsDescription
VITE_USER_NAVIGATION_STYLEsidebarsidebar, header, customApp navigation layout (personal + team)
VITE_HOME_SIDEBAR_COLLAPSEDfalsetrue, falseSidebar collapsed default state
VITE_SIDEBAR_COLLAPSIBLE_STYLEiconoffcanvas, icon, noneCollapse behavior
VITE_ENABLE_SIDEBAR_TRIGGERtruetrue, falseShow collapse toggle

Common Mistakes

Too many items in header layout: Header navigation works best with 3-5 top-level items. More than that causes horizontal overflow or cramped spacing. Use sidebar layout for complex navigation.

Forgetting mobile behavior: Sidebar layout automatically converts to a slide-out drawer on mobile. Test both layouts on narrow viewports.

Not updating translations: Navigation labels use translation keys. Adding items without corresponding translations shows raw keys like common.routes.analytics.

Verification

After changing layout configuration:

  1. Clear your browser's local storage (layout preferences are cached)
  2. Restart the dev server for environment variable changes
  3. Test both personal account and team account workspaces
  4. Verify mobile responsiveness at 375px viewport width
  5. Check that sidebar collapse/expand works correctly

Frequently Asked Questions

Can I use different layouts for personal and team accounts?
The dashboard uses a single navigation config (VITE_USER_NAVIGATION_STYLE) for both personal and team accounts, since the active account is DB-resolved rather than URL-scoped. To vary the UI by account type, branch on account.is_personal_account from useWorkspace() inside your components.
How do I create a completely custom layout?
Set the navigation style to 'custom' and implement your own layout component. You'll need to modify the shell files in apps/web/src/routes/_authenticated/dashboard/route.tsx and settings/route.tsx to use your custom navigation component.
Why isn't my sidebar staying collapsed?
User preferences are stored in local storage and override environment defaults. Clear local storage or use the browser's incognito mode to test default behavior.
How do I add icons to navigation items?
Import icons from lucide-react and pass them as the Icon prop. Use className='w-4' to maintain consistent sizing with other navigation icons.

Next Steps