Skip to content

feat(VNavRail): New VNavRail Component - #23094

Open
vstyler96 wants to merge 7 commits into
vuetifyjs:devfrom
vstyler96:v-nav-rail
Open

feat(VNavRail): New VNavRail Component#23094
vstyler96 wants to merge 7 commits into
vuetifyjs:devfrom
vstyler96:v-nav-rail

Conversation

@vstyler96

Copy link
Copy Markdown
Contributor

Description

This PR adds a new VNavRail component (plus its VNavRailItem child), a vertical Material 3 navigation rail for switching between top-level destinations.

VNavRail is a layout item (like VBottomNavigation/VNavigationDrawer), so it anchors to the start/end edge and offsets VMain automatically. It supports location (start/end/left/right, RTL-aware), width, align, active, plus the usual color/bgColor/border/elevation/rounded/theme props, and prepend/default/append slots. When active it is elevated by default.

VNavRailItem renders the M3 item — an icon button with a label below — and:

  • Uses useLink for route-based selection (to/exact/href/replace), so the active item is derived from the current route.
  • Draws the M3 active-indicator pill (56×32) and swaps to active-icon when selected, falling back to icon when active-icon is not provided.
  • Accepts the same variant set as VBtn (elevated, tonal, outlined, text, …, default tonal) and color, applied with the correct "on" color when active.
  • Sets aria-label from title on the icon button for accessibility.

API docs (locale descriptions + page-to-api mapping) are included.

Markup:

<template>
  <v-app>
    <v-nav-rail color="primary">
      <template #prepend>
        <v-btn icon="mdi-menu" variant="text" />
      </template>

      <v-nav-rail-item
        title="Home"
        icon="mdi-home-outline"
        active-icon="mdi-home"
        :to="{ path: '/' }"
        exact
      />
      <v-nav-rail-item
        title="Page 1"
        icon="mdi-numeric-1-box-outline"
        active-icon="mdi-numeric-1-box"
        variant="elevated"
        :to="{ path: '/page1' }"
      />
      <v-nav-rail-item
        title="Page 2"
        icon="mdi-numeric-2-box-outline"
        active-icon="mdi-numeric-2-box"
        variant="elevated"
        :to="{ path: '/page2' }"
      />
      <v-nav-rail-item
        title="Disabled"
        icon="mdi-cancel"
        disabled
      />

      <template #append>
        <v-btn icon="mdi-cog" variant="text" />
      </template>
    </v-nav-rail>

    <v-main>
      <v-container>
        <router-view />
      </v-container>
    </v-main>
  </v-app>
</template>

<script>
  export default {
    name: 'Playground',
  }
</script>

Note

The markup above uses <router-view> so route-based selection is visible. Wire the dev router (packages/vuetify/dev/router.js) with /, /page1, /page2 routes to see the active pill switch as you navigate.

@vstyler96
vstyler96 changed the base branch from master to dev August 11, 2026 03:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants