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>