Skip to content

Sidebar Navigation

A responsive navigation pattern using a drawer for mobile/compact views and a persistent section for larger layouts.

Demo

Implementation

vue
<script setup lang="ts">
import { ref } from 'vue';

// 1. Component Imports (Default)
import CLDrawer from '@codeandfunction/callaloo/CLDrawer';
import CLNavSection from '@codeandfunction/callaloo/CLNavSection';
import CLNavLink from '@codeandfunction/callaloo/CLNavLink';
import CLButton from '@codeandfunction/callaloo/CLButton';
import CLHeading from '@codeandfunction/callaloo/CLHeading';
import CLText from '@codeandfunction/callaloo/CLText';

import type { CLNavItem } from '@codeandfunction/callaloo';

// 2. Enum & Type Imports (Named)
import { 
  CLColors, 
  CLDrawerPosition,
  CLHeadingLevels,
  CLIconNames,
  CLOrientation,
  CLButtonTypes,
  CLTextTypes
} from '@codeandfunction/callaloo';

// 3. State & Logic
const isDrawerOpen = ref(false);

const mainNavItems: CLNavItem[] = [
  { ariaLabel: 'Go to Dashboard', href: '#', id: 'home', label: 'Dashboard' },
  { ariaLabel: 'View Projects', href: '#', id: 'projects', label: 'Projects' },
  { ariaLabel: 'Manage Tasks', href: '#', id: 'tasks', label: 'Tasks' },
  { ariaLabel: 'View Team', href: '#', id: 'team', label: 'Team' },
];

const secondaryNavItems: CLNavItem[] = [
  { ariaLabel: 'Account Settings', href: '#', id: 'settings', label: 'Settings' },
  { ariaLabel: 'Get Help', href: '#', id: 'help', label: 'Help & Support' },
];

const toggleDrawer = (): void => {
  isDrawerOpen.value = !isDrawerOpen.value;
};

const closeDrawer = (): void => {
  isDrawerOpen.value = false;
};
</script>

<template>
  <div class="pattern-preview">
    <div class="sidebar-demo">
      <div class="demo-toolbar">
        <CLButton 
          @click="toggleDrawer" 
          :color="CLColors.Primary"
          :icon-before="CLIconNames.Menu"
          :type="CLButtonTypes.Button"
        >
          Open Navigation
        </CLButton>
      </div>
      <div class="demo-content">
        <CLHeading :level="CLHeadingLevels.H3">Main Application Area</CLHeading>
        <CLText :type="CLTextTypes.Body">
          Click the button above to toggle the sidebar navigation drawer.
        </CLText>
      </div>
      <CLDrawer 
        :is-open="isDrawerOpen" 
        :on-close="closeDrawer"
        :position="CLDrawerPosition.Left"
        auto-size
      >
        <div class="sidebar-content">
          <div class="sidebar-header">
            <CLHeading :level="CLHeadingLevels.H4">Callaloo App</CLHeading>
          </div>
          <div class="nav-group">
            <CLText :type="CLTextTypes.Tiny" :color="CLColors.Neutral">MAIN MENU</CLText>
            <CLNavSection 
              :nav-items="mainNavItems" 
              :type="CLOrientation.Vertical" 
              :color="CLColors.Primary"
            />
          </div>
          <div class="nav-group">
            <CLText :type="CLTextTypes.Tiny" :color="CLColors.Neutral">SYSTEM</CLText>
            <CLNavSection 
              :nav-items="secondaryNavItems" 
              :type="CLOrientation.Vertical" 
              :color="CLColors.Neutral"
            />
          </div>
          <div class="sidebar-footer">
            <CLNavLink href="#" :color="CLColors.Danger">
              Logout
            </CLNavLink>
          </div>
        </div>
      </CLDrawer>
    </div>
  </div>
</template>

<style scoped>
  .pattern-preview {
    display: flex;
    flex-direction: column;
    flex: 1;
  }
  .sidebar-demo {
    display: flex;
    flex-direction: column;
    flex: 1;
    gap: 1rem;
    height: 100%;
  }
  .demo-content {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    border: 2px dashed var(--vp-c-divider);
    border-radius: 8px;
    padding: 2rem;
    text-align: center;
  }
  .sidebar-content {
    display: flex;
    flex-direction: column;
    height: 100%;
    padding: 1.5rem;
    gap: 2rem;
    width: 280px;
  }
  .sidebar-header {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--clll-divider-color, #eee);
  }
  .nav-group {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
  }
  .sidebar-footer {
    margin-top: auto;
    padding-top: 1rem;
    border-top: 1px solid var(--clll-divider-color, #eee);
  }
</style>

Released under the MIT License.