DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Top 5 Gantt Chart Libraries for Vue.js
  • Validation Forms in Vue.js Apps Using Vuelidate library
  • Building a Simple Todo App With Model Context Protocol (MCP)
  • Mastering React App Configuration With Webpack

Trending

  • AI-Based Threat Detection in Cloud Security
  • Performance Optimization Techniques for Snowflake on AWS
  • Scalable System Design: Core Concepts for Building Reliable Software
  • Unlocking AI Coding Assistants Part 3: Generating Diagrams, Open API Specs, And Test Data
  1. DZone
  2. Coding
  3. JavaScript
  4. Don't Forget Browser Button UX In Your Vue.js App

Don't Forget Browser Button UX In Your Vue.js App

A Vue.js whiz explains how to create different kinds of browser navigation using this powerful JavaScript framework. Read on for more!

By 
Anthony Gore user avatar
Anthony Gore
DZone Core CORE ·
Updated Feb. 10, 20 · Tutorial
Likes (4)
Comment
Save
Tweet
Share
10.5K Views

Join the DZone community and get the full member experience.

Join For Free

when building single-page applications many vue developers forget about ux for browser button navigation. they mistakenly assume that this kind of navigation is the same as hyperlink navigation when in fact it can be quite different.

unlike hyperlink navigation, if a user goes forward and back between pages they expect the page to still look like it did when they return or they'll consider the ux "weird" or "annoying."

for example, if i were browsing a thread on hacker news and i scroll down to a comment and collapse it, then i clicked through to another page, then i clicked "back," i'd expect to still be scrolled down to the comment and for it to still be collapsed!

image title

in a vue.js app, though, this is not the default behavior; scroll position and app data are not persisted by default. we need to consciously set up our app to ensure we have a smooth and predictable ux for the browser navigation buttons.

configuring vue router

vue router's role in the optimal back and forward ux is in controlling scroll behavior . a user's expectations with this would be:

  • when moving back and forward, return to the previous scroll position.
  • when navigating by links, scroll to the top.

we can achieve this by adding a scrollbehavior callback to our router configuration. note that savedposition is made available when using the browser back and forward buttons and not when using hyperlinks.

const scrollbehavior = (to, from, savedposition) => {
  if (savedposition) {
    return savedposition
  } else {
      position.x = 0
      position.y = 0
    }
    return position
  }
}

const router = new vuerouter({
  mode: 'history',
  scrollbehavior,
  routes: []
})

more comprehensive scroll behavior settings can be found in this example .

state persistence

even more critical than scroll behavior is persisting the state of the app. for example, if a user makes a selection on page 1, then navigates to page 2, then back to page 1, they expect the selection to be persisted.

in the naive implementation below, foo 's checked state will not persist between route transitions. when the route changes, vue destroys foo and replaces it with home , or vice versa. as we know with components, the state is created freshly on each mount.

const foo = vue.component('foo', {
  template: '<div @click="checked = !checked">{{ message }}</div>',
  data () {
    return { checked: false }; 
  }
  computed: {
    message() {
      return this.checked ? 'checked' : 'not checked';
    }
  }
});

const router = new vuerouter({
  mode: 'history',
  scrollbehavior,
  routes: [
    { path: '/', component: home },
    { path: '/bar', component: foo }
  ]
});

this would be equivalent to uncollapsing all the comments you collapsed in hacker news when you navigate back to an article's comments, i.e. very annoying!

keep-alive

the special keep-alive component can be used to alleviate this problem. it tells vue not to destroy any child components when they're no longer in the dom, but instead, keep them in memory. this is useful not just for a route transition, but even when v-if takes a component in and out of a page.

<div id="app">
  <keep-alive>
    <router-view></router-view>
  </keep-alive>
</div>

the advantage of using keep-alive is that's it's very easy to setup; it can be simply wrapped around a component and it works as expected.

vuex

there's a scenario where keep-alive will not be sufficient: what if the user refreshes the page or clicks back and forward to another website? the data would be wiped and we're back to square one. a more robust solution than keep-alive is to use the browser's local storage to persist component state.

since html5, we've been able to use the browser to store a small amount of arbitrary data. the easiest way to do this is to first set up a vuex store. any data that needs to be cached between route transitions or site visits go in the store. later we will persist it to local storage.

let's now modify our example above to use vuex to store foo 's checked state:

const store = new vuex.store({
  state: {
    checked: false
  },
  mutations: {
    updatechecked(state, payload) {
      state.checked = payload;
    }
  }
});

const foo = vue.component('foo', {
  template: '<div @click="checked">{{ message }}</div>',
  methods: {
    checked() {
      this.$store.commit('updatechecked', !this.$store.state.checked);
    }
  },
  computed: {
    message() {
      return this.$store.state.checked ? 'checked' : 'not checked';
    }
  }
});

we can now get rid of the keep-alive as changing the page will no longer destroy the state information about our component as vuex persists across routes.

local storage

now, every time the vuex store is updated, we want to store a snapshot of it in local storage. then when the app is first loaded we can check if there's any local storage and use it to seed our vuex store. this means that even if we navigate to another url we can persist our state.

fortunately, there's a tool for this already: vuex-localstorage . it's really easy to setup and integrate into vuex. below is everything you need to get it to do what was just described:

import createpersist from 'vuex-localstorage';

const store = new vuex.store({
  plugins: [ createpersist({
    namespace: 'test-app',
    initialstate: {},
    expires: 7 * 24 * 60 * 60 * 1000
  }) ],
  state: {
    checked: false
  },
  mutations: {
    updatechecked(state, payload) {
      state.checked = payload;
    }
  }
});

back and forward ux vs. hyperlink ux

you may want to differentiate behavior between the back and forward navigation and hyperlink navigation. we expect data in the back and forward navigation to persist, while in hyperlink navigation it should not.

for example, returning to hacker news, a user would expect comment collapse to be reset if you navigate with hyperlinks back to the front page and then back into a thread. try it for yourself and you'll notice this subtle difference in your expectation.

in a vue app, we can simply add a navigation guard to our home route where we can reset any state variables:

const router = new vuerouter({
  mode: 'history',
  scrollbehavior,
  routes: [
    { path: '/', component: home, beforeenter(to, from, next) {
      store.state.checked = false;
      next();
    } },
    { path: '/bar', component: foo }
  ]
});
app Vue.js

Published at DZone with permission of Anthony Gore, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Top 5 Gantt Chart Libraries for Vue.js
  • Validation Forms in Vue.js Apps Using Vuelidate library
  • Building a Simple Todo App With Model Context Protocol (MCP)
  • Mastering React App Configuration With Webpack

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!