Developer Docs
Quick reference guides with props tables, usage examples, and best practices for rapid development
NavigationList
🧭 NavigationList
Navigation menus with active state tracking, support for horizontal/vertical orientation, optional icons and badges, and built-in accessibility features.
Quick Example
🔧 Props Reference
All available props for the NavigationList component:
| Prop | Type | Default | Description |
|---|---|---|---|
| items | Array | [] | Navigation items array (objects with label, id, icon, badge, disabled, onClick) |
| activeItem | van.State | van.state(null) | Currently active item ID or index |
| orientation | string | 'vertical' | Layout orientation: 'vertical' or 'horizontal' |
| size | string | 'md' | Size variant: 'sm', 'md', 'lg' |
| onItemClick | Function | null | Callback when item clicked: (item, index) => {} |
| class | string | '' | Additional CSS classes |
Item Object Structure
| Prop | Type | Default | Description |
|---|---|---|---|
| id | string | number | index | Unique identifier (uses array index if not provided) |
| label | string | required | Display text for the item |
| title | string | undefined | Alternative to label |
| icon | string | undefined | Oracle JET icon name (without oj-ux-ico- prefix) |
| badge | Object | undefined | Badge object (see Badge component props) |
| disabled | boolean | false | Disable the item |
| onClick | Function | undefined | Item-specific click handler |
💻 Basic Usage
Simple navigation menu examples with vertical and horizontal orientations:
Vertical Navigation (Default)
const activeItem = van.state(0);
const items = [
{ label: 'Dashboard' },
{ label: 'Services' },
{ label: 'Profile' },
{ label: 'Settings' }
];
NavigationList({
items,
activeItem
})Horizontal Navigation
NavigationList({
items,
activeItem,
orientation: 'horizontal'
})🎨 With Icons
Add icons to navigation items for better visual hierarchy:
const items = [
{ id: 'dashboard', label: 'Dashboard', icon: 'home' },
{ id: 'services', label: 'Services', icon: 'grid' },
{ id: 'messages', label: 'Messages', icon: 'message' },
{ id: 'settings', label: 'Settings', icon: 'settings' }
];
NavigationList({
items,
activeItem: van.state('dashboard')
})🔔 With Badges
Display notification counts and status indicators with badges:
const items = [
{
id: 'inbox',
label: 'Inbox',
icon: 'inbox',
badge: { label: '12', variant: 'solid', semantic: 'info' }
},
{ id: 'sent', label: 'Sent', icon: 'sent' },
{
id: 'drafts',
label: 'Drafts',
icon: 'draft',
badge: { label: '3', variant: 'subtle', semantic: 'neutral' }
},
{ id: 'archive', label: 'Archive', icon: 'archive' }
];
NavigationList({
items,
activeItem: van.state('inbox')
})📏 Size Variants
Three size options to match your design context:
Small
NavigationList({ items, size: 'sm' })Medium (Default)
NavigationList({ items, size: 'md' })Large
NavigationList({ items, size: 'lg' })🚫 Disabled Items
Disable specific navigation items to prevent interaction:
const items = [
{ id: 'home', label: 'Home', icon: 'home' },
{ id: 'products', label: 'Products', icon: 'shopping-cart' },
{
id: 'premium',
label: 'Premium Features',
icon: 'star',
disabled: true // Grayed out, not clickable
},
{ id: 'settings', label: 'Settings', icon: 'settings' }
];
NavigationList({ items, activeItem: van.state('home') })🖱️ Click Handlers
Handle navigation clicks with global or per-item handlers:
Global Handler
const activeItem = van.state('dashboard');
NavigationList({
items,
activeItem,
onItemClick: (item, index) => {
console.log('Clicked:', item.label);
// Navigation logic here
router.navigate(`/${item.id}`);
}
})Per-Item Handler
const items = [
{
id: 'dashboard',
label: 'Dashboard',
onClick: () => router.navigate('/dashboard')
},
{
id: 'services',
label: 'Services',
onClick: () => router.navigate('/services')
},
{
id: 'settings',
label: 'Settings',
onClick: () => showSettings.val = true // Open modal instead
}
];
NavigationList({ items, activeItem })⚡️ Best Practices
✓ Do This
✓Use unique IDs for items (not array indices)
✓Keep labels short and clear (1-2 words)
✓Use icons for better visual scanning
✓Show badges for counts/notifications
✓Disable items that are unavailable
✓Use horizontal for top navigation
✓Use vertical for sidebars
✗ Avoid This
✗Use long labels (wrap is ugly)
✗Mix icons and non-icons in same list
✗Use badges for decorative purposes
✗Hide disabled items (show but disable)
✗Forget to set activeItem
✗Use too many navigation items (>8)
✗Nest NavigationLists
✨ Key Features
Active State Tracking
Automatic visual feedback for current page/section
Flexible Orientation
Vertical for sidebars, horizontal for top navigation
Icon Support
Oracle JET icons for better visual hierarchy
Badge Integration
Show counts, notifications, or status indicators
Accessible
ARIA navigation role, aria-current for active items
Disabled State
Visual feedback for unavailable items
💡 Common Use Cases
Common patterns for implementing NavigationList in your applications:
1. Sidebar Navigation
const activePage = van.state('dashboard');
const sidebarItems = [
{ id: 'dashboard', label: 'Dashboard', icon: 'home' },
{ id: 'services', label: 'Services', icon: 'grid' },
{ id: 'messages', label: 'Messages', icon: 'message' },
{ id: 'profile', label: 'Profile', icon: 'person' },
{ id: 'settings', label: 'Settings', icon: 'settings' }
];
div(
{ class: 'w-64 h-screen bg-white border-r border-mist p-4' },
// Logo
div({ class: 'mb-6' }, Logo()),
// Navigation
NavigationList({
items: sidebarItems,
activeItem: activePage,
onItemClick: (item) => router.navigate(`/${item.id}`)
})
)2. Top Navigation Bar
const activeSection = van.state('home');
const topNavItems = [
{ id: 'home', label: 'Home' },
{ id: 'about', label: 'About' },
{ id: 'services', label: 'Services' },
{ id: 'contact', label: 'Contact' }
];
div(
{ class: 'bg-white border-b border-mist px-8 py-4' },
div(
{ class: 'max-w-7xl mx-auto flex items-center justify-between' },
Logo(),
NavigationList({
items: topNavItems,
activeItem: activeSection,
orientation: 'horizontal',
onItemClick: (item) => router.navigate(`/${item.id}`)
})
)
)3. Settings/Tabs Navigation
const activeTab = van.state('account');
const settingsTabs = [
{ id: 'account', label: 'Account', icon: 'person' },
{ id: 'privacy', label: 'Privacy', icon: 'lock' },
{ id: 'notifications', label: 'Notifications', icon: 'bell' },
{ id: 'billing', label: 'Billing', icon: 'credit-card' }
];
div(
{ class: 'grid md:grid-cols-[240px_1fr] gap-6' },
// Sidebar tabs
NavigationList({
items: settingsTabs,
activeItem: activeTab
}),
// Content area
() => renderSettingsContent(activeTab.val)
)4. Inbox/Mail Navigation
const activeFolder = van.state('inbox');
const unreadCount = van.state(12);
const mailFolders = [
{
id: 'inbox',
label: 'Inbox',
icon: 'inbox',
badge: {
label: () => `${unreadCount.val}`,
variant: 'solid',
semantic: 'info'
}
},
{ id: 'sent', label: 'Sent', icon: 'sent' },
{ id: 'drafts', label: 'Drafts', icon: 'draft' },
{ id: 'archive', label: 'Archive', icon: 'archive' },
{ id: 'trash', label: 'Trash', icon: 'trash' }
];
NavigationList({
items: mailFolders,
activeItem: activeFolder,
onItemClick: (item) => {
loadFolder(item.id);
}
})5. Responsive Mobile Menu
const activeItem = van.state('home');
const menuOpen = van.state(false);
const menuItems = [
{ id: 'home', label: 'Home', icon: 'home' },
{ id: 'discover', label: 'Discover', icon: 'explore' },
{ id: 'favorites', label: 'Favorites', icon: 'heart' },
{ id: 'profile', label: 'Profile', icon: 'person' }
];
div(
// Mobile: Overlay menu
() => menuOpen.val ? div(
{
class: 'fixed inset-0 bg-black/50 z-50 md:hidden',
onclick: () => menuOpen.val = false
},
div(
{
class: 'absolute top-0 left-0 w-64 h-full bg-white p-4',
onclick: (e) => e.stopPropagation()
},
NavigationList({
items: menuItems,
activeItem,
onItemClick: (item) => {
router.navigate(`/${item.id}`);
menuOpen.val = false;
}
})
)
) : '',
// Desktop: Always visible sidebar
div(
{ class: 'hidden md:block w-64 border-r border-mist p-4' },
NavigationList({
items: menuItems,
activeItem,
onItemClick: (item) => router.navigate(`/${item.id}`)
})
)
)🔗 Integration with Router
NavigationList integrates seamlessly with the file-based router:
Auto-sync with URL
import { router } from 'utils/fileBasedRouterV2.js';
import { navigationPath } from 'utils/state.js';
// Initialize activeItem from current route
const activeItem = van.state(
navigationPath.val.split('/')[1] || 'dashboard'
);
// Update activeItem when route changes
navigationPath.subscribe((path) => {
const section = path.split('/')[1];
activeItem.val = section;
});
NavigationList({
items: [
{ id: 'dashboard', label: 'Dashboard' },
{ id: 'services', label: 'Services' },
{ id: 'profile', label: 'Profile' }
],
activeItem,
onItemClick: (item) => router.navigate(`/${item.id}`)
})Explore More Components
Browse other component categories