How to Easily Create Beautiful App Bars in Vuetify

An app bar is an important part of every user interface and is typically the primary source of site navigation. Like a toolbar, it is displayed at the top of the screen and can be combined with a navigation drawer or tabs. In this article, we’re going to learn how to create and customize app bars with Vuetify.

The v-app-bar Component

Vuetify provides the v-app-bar component for creating app bars. We use the app prop on the component to make Vuetify consider the app bar when dynamically sizing other components, such as v-main.

<template>
  <v-app>
    <v-app-bar app></v-app-bar>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
An app bar.

App Bar Title

We can use the v-toolbar-title component to set the app bar title.

<template>
  <v-app>
    <v-app-bar app>
      <v-toolbar-title>Coding Beauty</v-toolbar-title>
    </v-app-bar>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
An app bar with a title.

Note: While we could use the v-app-bar-title component to set the app bar title, the Vuetify team does not recommend using it without the shrink-on-scroll prop (discussed later in this article), as it would add an unnecessary resize watcher and additional calculations.

App Bar Nav Icon

v-app-bar-nav-icon is a styled icon button component created specifically for use with a toolbar or app bar. An app bar nav icon is typically placed on the left side of the toolbar or app bar as a hamburger menu, and is often used to control the state of a navigation drawer. We can customize the icon and function of this component with the default slot.

<template>
  <v-app>
    <v-app-bar app>
      <v-app-bar-nav-icon> </v-app-bar-nav-icon>
      <v-toolbar-title>Coding Beauty</v-app-bar-title>
    </v-app-bar>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
An app bar with a nav icon.

App Bar Colors

The app bar component comes with the color prop for customizing the color of the app bar. The dark prop makes the color of the text white

<template>
  <v-app>
    <v-app-bar app color="green" dark>
      <v-app-bar-nav-icon> </v-app-bar-nav-icon>
      <v-app-bar-title>Coding Beauty</v-app-bar-title>
    </v-app-bar>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Customizing the app bar color.

Collapsed App Bar

Setting the collapse prop to true on the v-app-bar will collapse the app bar at all times:

<template>
  <v-app>
    <v-app-bar app color="primary" dark collapse>
      <v-app-bar-nav-icon> </v-app-bar-nav-icon>
      <v-app-bar-title>Collapsing Bar</v-app-bar-title>
    </v-app-bar>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
A collapsed app bar.

Collapse on Scroll

We can decide to use the collapse-on-scroll prop to collapse the app bar only when the user scrolls.

<template>
  <v-app>
    <v-app-bar app color="primary" dark collapse-on-scroll>
      <v-app-bar-nav-icon> </v-app-bar-nav-icon>
      <v-toolbar-title>Collapsing Bar</v-toolbar-title>
    </v-app-bar>
    <v-sheet>
      <v-container style="height: 1000px"> </v-container>
    </v-sheet>
  </v-app>
</template>

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

An app bar that collapses on scroll.

App Bar Actions

We can add functionality to the app bar that we want to be easily accessible to the user with icon buttons.

<template>
  <v-app>
    <v-app-bar app color="yellow accent-3">
      <v-app-bar-nav-icon> </v-app-bar-nav-icon>
      <v-toolbar-title>Coding Beauty</v-toolbar-title>
      <v-spacer></v-spacer>
      <v-btn icon> <v-icon> mdi-heart </v-icon> </v-btn>
      <v-btn icon>
        <v-icon>mdi-magnify</v-icon>
      </v-btn>
    </v-app-bar>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Adding functionality to the app bar with icon buttons.

App Bar Menu

We can also extend the functionality of the app bar with a menu component (v-menu).

<template>
  <v-app>
    <v-app-bar app color="deep-purple accent-4" dark>
      <v-app-bar-nav-icon> </v-app-bar-nav-icon>
      <v-toolbar-title>Coding Beauty</v-toolbar-title>
      <v-spacer></v-spacer>
      <v-btn icon> <v-icon> mdi-heart </v-icon> </v-btn>
      <v-btn icon>
        <v-icon>mdi-magnify</v-icon>
      </v-btn>
      <v-menu left bottom>
        <template v-slot:activator="{ on, attrs }">
          <v-btn icon v-bind="attrs" v-on="on">
            <v-icon>mdi-dots-vertical</v-icon>
          </v-btn>
        </template>

        <v-list>
          <v-list-item v-for="n in 4" :key="n" @click="() => {}">
            Option {{ n }}
          </v-list-item>
        </v-list>
      </v-menu>
    </v-app-bar>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
An app bar with a menu.

Clicking the menu icon button will display the popup containing the options we added:

Clicking the menu displays popup containing the options.

Dense App Bar

We can use the dense prop to make an app bar dense. A dense app bar has a lower height than a regular one.

<template>
  <v-app>
    <v-app-bar app color="deep-purple accent-4" dark dense>
      <v-app-bar-nav-icon> </v-app-bar-nav-icon>
      <v-toolbar-title>Coding Beauty</v-toolbar-title>
      <v-spacer></v-spacer>
      <v-btn icon> <v-icon> mdi-heart </v-icon> </v-btn>
      <v-btn icon>
        <v-icon>mdi-magnify</v-icon>
      </v-btn>
      <v-menu left bottom>
        <template v-slot:activator="{ on, attrs }">
          <v-btn icon v-bind="attrs" v-on="on">
            <v-icon>mdi-dots-vertical</v-icon>
          </v-btn>
        </template>

        <v-list>
          <v-list-item v-for="n in 4" :key="n" @click="() => {}">
            Option {{ n }}
          </v-list-item>
        </v-list>
      </v-menu>
    </v-app-bar>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
A dense app bar.

Elevate on Scroll

When we set the elevate-on-scroll prop to true, the app bar will rest at an elevation of 0dp until the user begins to scroll down. The elevation raises to 4dp once scrolling begins.

<template>
  <v-app>
    <v-app-bar app color="white" elevate-on-scroll>
      <v-app-bar-nav-icon> </v-app-bar-nav-icon>
      <v-toolbar-title>Coding Beauty</v-toolbar-title>
      <v-spacer></v-spacer>
      <v-btn icon> <v-icon> mdi-heart </v-icon> </v-btn>
      <v-btn icon>
        <v-icon>mdi-magnify</v-icon>
      </v-btn>
      <v-menu left bottom>
        <template v-slot:activator="{ on, attrs }">
          <v-btn icon v-bind="attrs" v-on="on">
            <v-icon>mdi-dots-vertical</v-icon>
          </v-btn>
        </template>

        <v-list>
          <v-list-item v-for="n in 4" :key="n" @click="() => {}">
            Option {{ n }}
          </v-list-item>
        </v-list>
      </v-menu>
    </v-app-bar>
    <v-sheet>
      <v-container style="height: 1000px"> </v-container>
    </v-sheet>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Making an app bar elevate on scroll.

Extending the App Bar with Tabs

We can extend the app bar with tabs by including the tabs in the extension slot of v-app-bar:

<template>
  <v-app>
    <v-app-bar app color="primary" dark>
      <v-app-bar-nav-icon> </v-app-bar-nav-icon>
      <v-toolbar-title>Coding Beauty</v-toolbar-title>
      <v-spacer></v-spacer>
      <v-btn icon>
        <v-icon>mdi-magnify</v-icon>
      </v-btn>
      <v-menu left bottom>
        <template v-slot:activator="{ on, attrs }">
          <v-btn icon v-bind="attrs" v-on="on">
            <v-icon>mdi-dots-vertical</v-icon>
          </v-btn>
        </template>
      </v-menu>

      <template v-slot:extension>
        <v-tabs align-with-title>
          <v-tab>Tab 1</v-tab>
          <v-tab>Tab 2</v-tab>
          <v-tab>Tab 3</v-tab>
        </v-tabs>
      </template>
    </v-app-bar>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Extending the app bar with tabs.

Prominent App Bar

Setting the prominent prop to true will increase its height.

<template>
  <v-app>
    <v-app-bar app color="primary" dark prominent>
      <v-app-bar-nav-icon> </v-app-bar-nav-icon>
      <v-toolbar-title>Title</v-toolbar-title>
      <v-spacer></v-spacer>
      <v-btn icon>
        <v-icon>mdi-magnify</v-icon>
      </v-btn>
      <v-menu left bottom>
        <template v-slot:activator="{ on, attrs }">
          <v-btn icon v-bind="attrs" v-on="on">
            <v-icon>mdi-dots-vertical</v-icon>
          </v-btn>
        </template>
      </v-menu>

      <template v-slot:extension>
        <v-tabs align-with-title>
          <v-tab>Tab 1</v-tab>
          <v-tab>Tab 2</v-tab>
          <v-tab>Tab 3</v-tab>
        </v-tabs>
      </template>
    </v-app-bar>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
A prominent app bar.

Shrink on Scroll

With the shrink-on-scroll prop, we can a prominent app bar reduce in height as the user scrolls down. This allows for a smooth transition to taking up less visual space when the user is scrolling through content.

<template>
  <v-app>
    <v-app-bar app color="primary" dark prominent shrink-on-scroll>
      <v-app-bar-nav-icon> </v-app-bar-nav-icon>
      <v-toolbar-title>Title</v-toolbar-title>
      <v-spacer></v-spacer>
      <v-btn icon>
        <v-icon>mdi-magnify</v-icon>
      </v-btn>
      <v-menu left bottom>
        <template v-slot:activator="{ on, attrs }">
          <v-btn icon v-bind="attrs" v-on="on">
            <v-icon>mdi-dots-vertical</v-icon>
          </v-btn>
        </template>
      </v-menu>

      <template v-slot:extension>
        <v-tabs align-with-title>
          <v-tab>Tab 1</v-tab>
          <v-tab>Tab 2</v-tab>
          <v-tab>Tab 3</v-tab>
        </v-tabs>
      </template>
    </v-app-bar>
    <v-sheet>
      <v-container style="height: 1000px"></v-container>
    </v-sheet>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Making an app bar shrink on scroll.

App Bar Images

We can display background images on the app bar with the src prop. When we set an image, the color prop acts as a fallback color that the app bar will display when the image has not yet loaded or fails to load.

<template>
  <v-app>
    <v-app-bar
      app
      color="primary"
      dark
      prominent
      src="https://picsum.photos/1920/1080?random"
    >
      <v-app-bar-nav-icon> </v-app-bar-nav-icon>
      <v-toolbar-title>Title</v-toolbar-title>
      <v-spacer></v-spacer>
      <v-btn icon>
        <v-icon>mdi-magnify</v-icon>
      </v-btn>
      <v-menu left bottom>
        <template v-slot:activator="{ on, attrs }">
          <v-btn icon v-bind="attrs" v-on="on">
            <v-icon>mdi-dots-vertical</v-icon>
          </v-btn>
        </template>
      </v-menu>

      <template v-slot:extension>
        <v-tabs align-with-title>
          <v-tab>Tab 1</v-tab>
          <v-tab>Tab 2</v-tab>
          <v-tab>Tab 3</v-tab>
        </v-tabs>
      </template>
    </v-app-bar>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Displaying an image on the app bar.

Fade Image on Scroll

We might want to make the background image on the app bar fade as the user scrolls down. We can do this with the fade-img-on-scroll prop. As we scroll, the image reduces in opacity until it totally fades away and we can only see the background color.

<template>
  <v-app>
    <v-app-bar
      app
      color="grey"
      dark
      prominent
      src="https://picsum.photos/1920/1080?random"
      fade-img-on-scroll
    >
      <v-app-bar-nav-icon> </v-app-bar-nav-icon>
      <v-app-bar-title>Title</v-app-bar-title>
      <v-spacer></v-spacer>
      <v-btn icon>
        <v-icon>mdi-magnify</v-icon>
      </v-btn>
      <v-menu left bottom>
        <template v-slot:activator="{ on, attrs }">
          <v-btn icon v-bind="attrs" v-on="on">
            <v-icon>mdi-dots-vertical</v-icon>
          </v-btn>
        </template>
      </v-menu>

      <template v-slot:extension>
        <v-tabs align-with-title>
          <v-tab>Tab 1</v-tab>
          <v-tab>Tab 2</v-tab>
          <v-tab>Tab 3</v-tab>
        </v-tabs>
      </template>
    </v-app-bar>
    <v-sheet>
      <v-container style="height: 1000px"> </v-container>
    </v-sheet>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Making the background image of the app bar fade on scroll.

Hide on Scroll

We can hide the app bar when the user starts to scroll with the hide-on-scroll prop.

<template>
  <v-app>
    <v-app-bar app color="teal" dark hide-on-scroll>
      <v-app-bar-nav-icon> </v-app-bar-nav-icon>
      <v-app-bar-title>Title</v-app-bar-title>
      <v-spacer></v-spacer>
      <v-btn icon>
        <v-icon>mdi-magnify</v-icon>
      </v-btn>
      <v-menu left bottom>
        <template v-slot:activator="{ on, attrs }">
          <v-btn icon v-bind="attrs" v-on="on">
            <v-icon>mdi-dots-vertical</v-icon>
          </v-btn>
        </template>
      </v-menu>
    </v-app-bar>
    <v-sheet>
      <v-container style="height: 1000px"> </v-container>
    </v-sheet>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Making the app bar hide on scroll.

Inverted Scroll

When the inverted-scroll prop is set to true, the app bar will hide until the user scrolls past the designated threshold. Once past the threshold, the app bar will continue to display until the user scrolls up past the threshold. If the scroll-treshold prop is not set, a default value of 0 will be used.

<template>
  <v-app>
    <v-app-bar app color="primary" dark inverted-scroll>
      <v-app-bar-nav-icon> </v-app-bar-nav-icon>
      <v-app-bar-title>Coding Beauty</v-app-bar-title>
      <v-spacer></v-spacer>
      <v-btn icon>
        <v-icon>mdi-magnify</v-icon>
      </v-btn>
      <v-menu left bottom>
        <template v-slot:activator="{ on, attrs }">
          <v-btn icon v-bind="attrs" v-on="on">
            <v-icon>mdi-dots-vertical</v-icon>
          </v-btn>
        </template>
      </v-menu>
    </v-app-bar>
    <v-sheet>
      <v-container style="height: 1000px"> </v-container>
    </v-sheet>
  </v-app>
</template>

<script>
export default {
  name: 'App',
};
</script>
Setting inverted scroll on an app bar.

Using an App Bar with a Navigation Drawer

We can add a navigation drawer to our user interface and use the functional v-nav-bar-icon component on the app bar to toggle its visibility.

<template>
  <v-app>
    <v-app-bar app color="green" dark>
      <v-app-bar-nav-icon @click="drawer = true"> </v-app-bar-nav-icon>
      <v-toolbar-title>Coding Beauty</v-toolbar-title>
    </v-app-bar>
    <v-navigation-drawer v-model="drawer" absolute temporary>
      <v-list nav dense>
        <v-list-item-group
          v-model="group"
          active-class="deep-purple--text text--accent-4"
        >
          <v-list-item>
            <v-list-item-icon>
              <v-icon>mdi-home</v-icon>
            </v-list-item-icon>
            <v-list-item-title>Home</v-list-item-title>
          </v-list-item>

          <v-list-item>
            <v-list-item-icon>
              <v-icon>mdi-account</v-icon>
            </v-list-item-icon>
            <v-list-item-title>Account</v-list-item-title>
          </v-list-item>
        </v-list-item-group>
      </v-list>
    </v-navigation-drawer>
  </v-app>
</template>

<script>
export default {
  name: 'App',
  data: () => ({
    drawer: false,
    group: null,
  }),
};
</script>
Using an app bar with a navigation drawer.

Conclusion

We can add an app bar to a user interface for quick and easy navigation. Vuetify provides the v-app-bar component for creating and customizing the behaviour and appearance of an app bar.



Every Crazy Thing JavaScript Does

A captivating guide to the subtle caveats and lesser-known parts of JavaScript.

Every Crazy Thing JavaScript Does

Sign up and receive a free copy immediately.

2 thoughts on “How to Easily Create Beautiful App Bars in Vuetify”

  1. Don’t know if this is a typo or things have changed, but in the “App Bar Images” section the v-app-bar uses an “image” prop, not a “src” prop. And when requiring a local image “require()” is not needed:

Leave a Comment

Your email address will not be published. Required fields are marked *