vwf .

Developer Docs

Quick reference guides with props tables, usage examples, and best practices for rapid development

Components/Docs/NavigationList

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:

PropTypeDefaultDescription
itemsArray[]Navigation items array (objects with label, id, icon, badge, disabled, onClick)
activeItemvan.Statevan.state(null)Currently active item ID or index
orientationstring'vertical'Layout orientation: 'vertical' or 'horizontal'
sizestring'md'Size variant: 'sm', 'md', 'lg'
onItemClickFunctionnullCallback when item clicked: (item, index) => {}
classstring''Additional CSS classes

Item Object Structure

PropTypeDefaultDescription
idstring | numberindexUnique identifier (uses array index if not provided)
labelstringrequiredDisplay text for the item
titlestringundefinedAlternative to label
iconstringundefinedOracle JET icon name (without oj-ux-ico- prefix)
badgeObjectundefinedBadge object (see Badge component props)
disabledbooleanfalseDisable the item
onClickFunctionundefinedItem-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