vwf .

Developer Docs

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

Components/Docs/NavigationDrawer

NavigationDrawer

Slide-out navigation drawer with user profile, quick actions, statistics, and trending content

NavigationDrawer

Slide-out navigation drawer that appears from the left side. Features organized navigation sections, quick links, and auto-close on navigation. Typically triggered by hamburger menu in NavigationHeader.

Try It Live

Click the button below to see the NavigationDrawer in action:

Key Features

✓Slides in from left with smooth animation

✓Dark overlay with auto-close on click

✓Organized navigation sections (Learn, Build, Resources)

✓Quick links grid for common pages

✓Auto-closes after navigation

✓Mobile-optimized 280px width

✓Z-index hierarchy (overlay 998, drawer 999)

✓Scrollable content area

🔧 Props Reference

NavigationDrawer accepts a single prop for controlling visibility:

PropTypeDefaultDescription
isOpenvan.State<boolean>requiredVanJS state controlling drawer visibility

Returns: [overlay, drawer] - Array of two sibling elements (spread in parent)

💻 Basic Usage

Simple example showing how to integrate NavigationDrawer with a toggle button:

import { NavigationDrawer } from 'shared-components/layout/NavigationDrawer.js';

// Create state
const isDrawerOpen = van.state(false);

// Render drawer (spread the array!)
div(
  // Hamburger button
  button({
    onclick: () => isDrawerOpen.val = true
  }, '☰ Menu'),

  // Drawer (returns [overlay, drawer])
  ...NavigationDrawer({
    isOpen: isDrawerOpen
  }),

  // Main content
  main(/* content */)
)

🔗 Integration with NavigationHeader

NavigationDrawer shares state with NavigationHeader for seamless integration:

import { NavigationHeader } from 'shared-components/layout/NavigationHeader.js';

// NavigationHeader already includes NavigationDrawer!
div(
  // Spread NavigationHeader (which returns [drawer, header])
  ...NavigationHeader({
    navLinks,
    dsktpNavLinks
  }),

  main(/* content */)
)

// The hamburger button in NavigationHeader controls the drawer
// No need to create separate isOpen state

📁 Navigation Structure

NavigationDrawer has a built-in navigation structure with 3 sections:

1. Learn Section

✓Overview

✓Authentication

✓Database

✓Routing

✓Framework Docs

2. Build Section

✓Components Hub

✓Forms

✓Buttons

✓Display

✓Feedback

✓Layout

✓Navigation

✓Playground

3. Resources Section

✓API Docs

✓Colors

✓Icons

✓Developer Tools

⚡ Quick Links

Top section shows 3 quick access links in a grid:

✓Home → /

✓Showcase → /showcase

✓Playground → /playground

🎨 Customization

To customize the navigation structure, edit the component source:

// In NavigationDrawer.js (lines 40-77)
const navigationSections = {
  mySection: {
    title: 'My Section',
    icon: 'oj-ux-ico-folder',
    items: [
      { label: 'Item 1', path: '/item1', icon: 'oj-ux-ico-page' },
      { label: 'Item 2', path: '/item2', icon: 'oj-ux-ico-page' }
    ]
  }
};

// Quick links customization (lines 79-83)
const quickLinks = [
  { label: 'Dashboard', icon: 'oj-ux-ico-home', path: '/dashboard' },
  { label: 'Services', icon: 'oj-ux-ico-grid', path: '/services' }
];

🚪 Auto-Close Behavior

NavigationDrawer automatically closes in several scenarios:

Drawer Closes On:

✓Clicking any navigation item

✓Clicking overlay (dark background)

✓Clicking X button in NavigationHeader

✓Programmatic state change (isOpen.val = false)

Implementation

const handleClose = () => {
  isOpen.val = false;
};

// Navigation items call handleClose + navigate
button({
  onclick: () => {
    handleClose();
    navigateTo(item.path);
  }
}, item.label)

✨ Animation Details

NavigationDrawer uses CSS transitions for smooth slide and fade animations:

Slide Animation

// Drawer slides from left
// Closed: -translate-x-full (off-screen left)
// Open:   translate-x-0 (visible)

// Overlay fades in/out
// Closed: opacity-0 pointer-events-none
// Open:   opacity-100

// Both use transition-transform/transition-opacity

Z-Index Hierarchy

// Overlay: z-[998]  (below drawer, above content)
// Drawer:  z-[999]  (topmost)
// Header:  z-50     (below both)

// This ensures proper stacking:
// 1. Page content (z-0)
// 2. Header (z-50)
// 3. Drawer overlay (z-998)
// 4. Drawer (z-999)

✅ Best Practices

Follow these guidelines for optimal NavigationDrawer implementation:

✓ Do This

✓Spread the returned array

✓Use with NavigationHeader

✓Organize navigation into sections

✓Keep items short and scannable

✓Use icons for visual scanning

✓Auto-close on navigation

✓Test scroll on long lists

✗ Avoid This

✗Nest the returned array

✗Forget to spread in parent

✗Have too many sections (>4)

✗Use long navigation labels

✗Forget mobile testing

✗Modify z-index without hierarchy

✗Remove auto-close behavior

🎮 Programmatic Control

Control NavigationDrawer programmatically by updating the state:

const isDrawerOpen = van.state(false);

// Open drawer
isDrawerOpen.val = true;

// Close drawer
isDrawerOpen.val = false;

// Toggle drawer
isDrawerOpen.val = !isDrawerOpen.val;

// React to state changes
van.derive(() => {
  console.log('Drawer is', isDrawerOpen.val ? 'open' : 'closed');
});

📦 Complete Example

Full implementation example with hamburger button and navigation drawer:

import van from 'vanjs-core';
import { NavigationDrawer } from 'shared-components/layout/NavigationDrawer.js';
import { Button } from 'shared-components/forms/Button.js';

const { div, main } = van.tags;

export const App = () => {
  // Create drawer state
  const isDrawerOpen = van.state(false);

  return div(
    // Header with menu button
    div(
      { class: 'bg-white border-b border-mist p-4 flex items-center gap-4' },

      // Hamburger button
      Button({
        class: 'vwfcolor-sky ghost',
        onclick: () => isDrawerOpen.val = true
      }, '☰'),

      div({ class: 'text-xl font-bold' }, 'My App')
    ),

    // Navigation drawer (spread array!)
    ...NavigationDrawer({
      isOpen: isDrawerOpen
    }),

    // Main content
    main(
      { class: 'container mx-auto p-4' },
      'Page content here'
    )
  );
};

🔧 Common Issues & Solutions

Solutions to common NavigationDrawer integration problems:

Issue: Drawer not appearing

// Check these:
// 1. Are you spreading the array?
...NavigationDrawer({ isOpen })  // ✓ Correct

// 2. Is isOpen actually changing?
console.log('isOpen:', isOpen.val);

// 3. Is it behind other elements?
// Check z-index of parent elements

Issue: Overlay not closing drawer

// Overlay already has handleClose on click
// If not working, check for:
// 1. Elements with higher z-index blocking overlay
// 2. CSS pointer-events: none on overlay

Issue: Navigation not working

// Ensure navigateTo is imported and working:
import { navigateTo } from 'utils/fileBasedRouterV2.js';

// Test navigation separately:
navigateTo('/test-page');

Explore More Components

Browse other component categories