Skip to main content

VNavigationDrawer

The VNavigationDrawer component is used to display navigation links in a sidebar. It supports multiple display modes including permanent, temporary, and rail variants, with optional touch gestures and expand-on-hover behavior.

Usage

<template>
  <v-navigation-drawer v-model="drawer">
    <v-list>
      <v-list-item
        v-for="item in items"
        :key="item.title"
        :to="item.to"
      >
        <template v-slot:prepend>
          <v-icon>{{ item.icon }}</v-icon>
        </template>
        <v-list-item-title>{{ item.title }}</v-list-item-title>
      </v-list-item>
    </v-list>
  </v-navigation-drawer>
</template>

<script setup>
import { ref } from 'vue'

const drawer = ref(true)
const items = [
  { title: 'Dashboard', icon: 'mdi-view-dashboard', to: '/dashboard' },
  { title: 'Account', icon: 'mdi-account', to: '/account' },
  { title: 'Settings', icon: 'mdi-cog', to: '/settings' },
]
</script>

Props

modelValue
boolean | null
default:"null"
Controls the visibility of the navigation drawer.
<v-navigation-drawer v-model="drawer">
  <!-- Content -->
</v-navigation-drawer>
location
'start' | 'end' | 'left' | 'right' | 'top' | 'bottom'
default:"'start'"
Sets the position of the navigation drawer.
<v-navigation-drawer location="end">
  <!-- Drawer on the right side -->
</v-navigation-drawer>
width
number | string
default:"256"
Sets the width of the navigation drawer in pixels.
<v-navigation-drawer :width="300">
  <!-- Content -->
</v-navigation-drawer>
rail
boolean | null
default:"null"
Condenses navigation drawer width to show only icons.
<v-navigation-drawer rail>
  <!-- Mini variant showing only icons -->
</v-navigation-drawer>
railWidth
number | string
default:"56"
Sets the width of the drawer when in rail mode.
<v-navigation-drawer rail :rail-width="72">
  <!-- Content -->
</v-navigation-drawer>
expandOnHover
boolean
default:"false"
When in rail mode, expands the drawer on hover.
<v-navigation-drawer rail expand-on-hover>
  <!-- Expands on hover -->
</v-navigation-drawer>
permanent
boolean
default:"false"
Makes the drawer permanent (always visible, no overlay).
<v-navigation-drawer permanent>
  <!-- Always visible -->
</v-navigation-drawer>
temporary
boolean
default:"false"
Makes the drawer temporary (overlays content, shows scrim).
<v-navigation-drawer temporary>
  <!-- Temporary overlay -->
</v-navigation-drawer>
persistent
boolean
default:"false"
Keeps drawer open when clicking the scrim.
<v-navigation-drawer temporary persistent>
  <!-- Clicking scrim won't close -->
</v-navigation-drawer>
floating
boolean
default:"false"
Makes the drawer float above the content without pushing it.
<v-navigation-drawer floating>
  <!-- Floating drawer -->
</v-navigation-drawer>
scrim
boolean | string
default:"true"
Controls the scrim overlay. Can be a boolean or color string.
<!-- No scrim -->
<v-navigation-drawer :scrim="false">
  <!-- Content -->
</v-navigation-drawer>

<!-- Custom scrim color -->
<v-navigation-drawer scrim="rgba(0,0,0,0.8)">
  <!-- Content -->
</v-navigation-drawer>
image
string
Specifies a background image for the drawer.
<v-navigation-drawer image="/path/to/image.jpg">
  <!-- Content -->
</v-navigation-drawer>
color
string
Applies specified color to the drawer background.
<v-navigation-drawer color="primary">
  <!-- Content -->
</v-navigation-drawer>
touchless
boolean
default:"false"
Disables touch gestures for opening/closing the drawer.
<v-navigation-drawer touchless>
  <!-- No touch gestures -->
</v-navigation-drawer>
disableResizeWatcher
boolean
default:"false"
Disables the automatic opening/closing based on screen size.
disableRouteWatcher
boolean
default:"false"
Disables automatic closing when route changes.
sticky
boolean
default:"false"
Makes the drawer stick to the top of the viewport when scrolling.
elevation
number | string
Sets the elevation (box-shadow) of the drawer.
<v-navigation-drawer elevation="8">
  <!-- Content -->
</v-navigation-drawer>
border
boolean | string | number
Applies a border to the drawer.
rounded
boolean | string | number
Applies border radius to the drawer.
tag
string
default:"'nav'"
Specifies the custom tag to use for the root element.
theme
string
Applies a specific theme to the drawer.
mobile
boolean | null
Overrides the mobile breakpoint detection.
mobileBreakpoint
number | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'
Sets the breakpoint at which the drawer becomes temporary.
name
string
Assigns a specific name for layout registration.
order
number | string
default:"0"
Adjusts the order in which the drawer appears in the layout.
absolute
boolean
default:"false"
Applies position: absolute to the drawer.
focusTrap
boolean
default:"false"
Traps focus within the drawer when open.
openDelay
number | string
Delay (in ms) before opening when using expand-on-hover.
closeDelay
number | string
Delay (in ms) before closing when using expand-on-hover.

Events

update:modelValue
(value: boolean) => void
Emitted when the drawer visibility changes.
<v-navigation-drawer @update:modelValue="onDrawerChange">
  <!-- Content -->
</v-navigation-drawer>
update:rail
(value: boolean) => void
Emitted when the rail state changes (typically from expand-on-hover).
<v-navigation-drawer
  rail
  expand-on-hover
  @update:rail="onRailChange"
>
  <!-- Content -->
</v-navigation-drawer>

Slots

default
slot
The default slot for drawer content.
prepend
slot
Slot for content at the top of the drawer (before default content).
<v-navigation-drawer>
  <template v-slot:prepend>
    <v-list-item title="User Name" subtitle="[email protected]">
      <template v-slot:prepend>
        <v-avatar color="primary">
          <v-icon>mdi-account</v-icon>
        </v-avatar>
      </template>
    </v-list-item>
  </template>
  
  <v-list>
    <!-- Navigation items -->
  </v-list>
</v-navigation-drawer>
append
slot
Slot for content at the bottom of the drawer (after default content).
<v-navigation-drawer>
  <v-list>
    <!-- Navigation items -->
  </v-list>
  
  <template v-slot:append>
    <div class="pa-2">
      <v-btn block>
        Logout
      </v-btn>
    </div>
  </template>
</v-navigation-drawer>
image
slot
Slot for custom background image content. Receives { image: string } as slot props.
<v-navigation-drawer image="/bg.jpg">
  <template v-slot:image="{ image }">
    <v-img :src="image" gradient="to top, rgba(0,0,0,.7), rgba(0,0,0,.7)" />
  </template>
</v-navigation-drawer>

Examples

Basic Drawer

<template>
  <v-app>
    <v-app-bar>
      <v-app-bar-nav-icon @click="drawer = !drawer"></v-app-bar-nav-icon>
      <v-toolbar-title>Application</v-toolbar-title>
    </v-app-bar>

    <v-navigation-drawer v-model="drawer">
      <v-list>
        <v-list-item
          v-for="item in items"
          :key="item.title"
          :to="item.to"
        >
          <template v-slot:prepend>
            <v-icon>{{ item.icon }}</v-icon>
          </template>
          <v-list-item-title>{{ item.title }}</v-list-item-title>
        </v-list-item>
      </v-list>
    </v-navigation-drawer>

    <v-main>
      <!-- Content -->
    </v-main>
  </v-app>
</template>

<script setup>
import { ref } from 'vue'

const drawer = ref(true)
const items = [
  { title: 'Home', icon: 'mdi-home', to: '/' },
  { title: 'About', icon: 'mdi-information', to: '/about' },
  { title: 'Contact', icon: 'mdi-email', to: '/contact' },
]
</script>

Permanent Drawer

<template>
  <v-app>
    <v-navigation-drawer permanent>
      <v-list>
        <v-list-item title="Dashboard" prepend-icon="mdi-view-dashboard"></v-list-item>
        <v-list-item title="Settings" prepend-icon="mdi-cog"></v-list-item>
      </v-list>
    </v-navigation-drawer>

    <v-main>
      <!-- Content automatically adjusts -->
    </v-main>
  </v-app>
</template>

Rail Mode with Expand on Hover

<template>
  <v-app>
    <v-navigation-drawer rail expand-on-hover>
      <v-list density="compact" nav>
        <v-list-item
          prepend-icon="mdi-home"
          title="Home"
          value="home"
        ></v-list-item>
        <v-list-item
          prepend-icon="mdi-account"
          title="Account"
          value="account"
        ></v-list-item>
        <v-list-item
          prepend-icon="mdi-account-group"
          title="Users"
          value="users"
        ></v-list-item>
      </v-list>
    </v-navigation-drawer>

    <v-main>
      <!-- Content -->
    </v-main>
  </v-app>
</template>
When using rail mode with expand-on-hover, the drawer shows only icons by default and expands to show text when hovering.

With Image Background

<template>
  <v-navigation-drawer
    image="https://picsum.photos/1920/1080?random"
    theme="dark"
  >
    <template v-slot:prepend>
      <v-list-item
        title="John Doe"
        subtitle="[email protected]"
      >
        <template v-slot:prepend>
          <v-avatar color="primary">
            <v-icon>mdi-account</v-icon>
          </v-avatar>
        </template>
      </v-list-item>
    </template>

    <v-divider></v-divider>

    <v-list density="compact" nav>
      <v-list-item prepend-icon="mdi-home" title="Home"></v-list-item>
      <v-list-item prepend-icon="mdi-email" title="Messages"></v-list-item>
      <v-list-item prepend-icon="mdi-cog" title="Settings"></v-list-item>
    </v-list>
  </v-navigation-drawer>
</template>

Right-Side Drawer

<template>
  <v-app>
    <v-app-bar>
      <v-toolbar-title>Application</v-toolbar-title>
      <v-spacer></v-spacer>
      <v-btn icon @click="drawer = !drawer">
        <v-icon>mdi-menu</v-icon>
      </v-btn>
    </v-app-bar>

    <v-navigation-drawer v-model="drawer" location="end" temporary>
      <v-list>
        <v-list-item title="Settings" prepend-icon="mdi-cog"></v-list-item>
        <v-list-item title="Help" prepend-icon="mdi-help-circle"></v-list-item>
      </v-list>
    </v-navigation-drawer>

    <v-main>
      <!-- Content -->
    </v-main>
  </v-app>
</template>

<script setup>
import { ref } from 'vue'

const drawer = ref(false)
</script>

With Prepend and Append

<template>
  <v-navigation-drawer>
    <template v-slot:prepend>
      <v-list-item
        title="My Application"
        subtitle="v1.0.0"
      >
        <template v-slot:prepend>
          <v-avatar color="primary">
            <v-icon>mdi-application</v-icon>
          </v-avatar>
        </template>
      </v-list-item>
    </template>

    <v-divider></v-divider>

    <v-list density="compact" nav>
      <v-list-item prepend-icon="mdi-view-dashboard" title="Dashboard"></v-list-item>
      <v-list-item prepend-icon="mdi-account-multiple" title="Users"></v-list-item>
      <v-list-item prepend-icon="mdi-chart-line" title="Analytics"></v-list-item>
    </v-list>

    <template v-slot:append>
      <div class="pa-2">
        <v-btn block color="primary">
          Logout
        </v-btn>
      </div>
    </template>
  </v-navigation-drawer>
</template>
By default, temporary drawers close when the route changes. Use disable-route-watcher to prevent this behavior.

Behavior Modes

Temporary

  • Overlays content
  • Shows scrim (overlay)
  • Automatically becomes temporary on mobile devices
  • Closes on route change (unless disabled)

Permanent

  • Always visible
  • No scrim
  • Content adjusts to make space
  • Does not close on route change

Persistent

  • Similar to temporary
  • Doesn’t close when clicking scrim
  • Must be closed explicitly

Build docs developers (and LLMs) love