title: Vue router in-out page transition: transition in a new route while old route remains visible
body: <p>To illustrate what I'm trying to achieve but also discuss and learn about each mechanism separately, I split the issue into two independent challenges:</p>
  <p><strong>1. Keep previous route visible until new route has transitioned in</strong></p>
  <p>Whether the transition is sliding, what I'm trying here, or just fading; mode <code>in-out</code> doesn't work as I would expect it, namely that the existing route stays visible until the next route has finished its transition (e.g. overlaid itself over the previous one), exactly as illustrated here in the last example of this section <a href="https://v2.vuejs.org/v2/guide/transitions.html#Transition-Modes" rel="nofollow noreferrer">https://v2.vuejs.org/v2/guide/transitions.html#Transition-Modes</a>, showing two buttons with <code>in-out</code> mode. Instead no transition is happening but it just flips the routes statically at half of the given transition time.</p>
  <p>Is there any caveat with routes and an obvious reason why this wouldn't work the same way, e.g. that a single <code>router-view</code> can only hold one at the time and therefore in-out is not possible?</p>
  <p><strong>EDIT 1:</strong></p>
  <p>I figured out that <code>in-out</code> would actually only work with <code>position:absolute</code> on both elements, otherwise they will not overlay. Any idea how I could elegantly include such a behavior, potentially setting that absolute position during router-transition only?</p>
  <p>Current hack that has the visual slide-up modal effect (mode: in-out) I'm looking for: adding <code>style=&quot;position:absolute; z-index:2100&quot;</code> to the dialog route. Then I would need to change the underlying transition once it's shown in order to have the reverse hide effect (mode: out-in).</p>
  <p>Also see <strong>EDIT 2</strong> below.</p>
  <hr />
  <p><strong>2. Creating a modal-like page (route) which opens above another existing page when navigated to</strong></p>
  <p>I tried to hack that behavior by adding a second router-view in App.vue</p>
  <pre><code>&lt;router-view /&gt;
  &lt;router-view name=&quot;dialog&quot; /&gt;
  </code></pre>
  <p>The particular component is added to my routes like this</p>
  <pre><code>{
      path: 'records/new',
      components: {
        dialog: () =&gt; import('layouts/NewRecord.vue')
      },
      children: [
        {
          name: 'new-record',
          path: '',
          component: () =&gt;
            import('src/pages/NewRecord.vue')
        }
      ]
    }
  </code></pre>
  <p>I'm not sure whether this approach even makes sense but I couldn't make it work properly. The aim would be to just overlay another <code>router-view name=&quot;dialog</code> whenever a &quot;dialog&quot;-path is pushed, so while it can be animated (slide-up) the other router-view stays visible below. In the end I guess I'm facing the same issue here: once the route changes, the initial router-view discards its component because the path does not match the current location anymore.</p>
  <p>Either way, there are people out there with more experience and expertise so I hope I could illustrate what I'm trying to achieve and I'm just curious and thankful to read your inputs.</p>
  <p><strong>EDIT 2</strong></p>
  <p>I could make it work the way I wanted with simply one , wrapped in a custom <code>page-transition</code> component. It is quite a hack though AND I needed to add <code>position: absolute</code> to may page-layouts, to all of them actually (both the &quot;leaving&quot; and the &quot;entering&quot; component need <code>position: absolute</code>) when showing the dialog component. I'm sure there's a better way but I haven't found it so far.</p>
  <p>Custom page-transition component:</p>
  <pre><code>&lt;template&gt;
      &lt;transition :name=&quot;name&quot; :mode=&quot;mode&quot;&gt;
          &lt;slot/&gt;
      &lt;/transition&gt;
  &lt;/template&gt;
  
  &lt;script lang=&quot;ts&quot;&gt;
    import { Component, Watch } from 'vue-property-decorator'
    import Vue from 'vue'
    import { Route } from 'vue-router'
  
    @Component({
      components: {}
    })
    export default class PageTransition extends Vue {
      NAME_FADE = 'fade'
      NAME_SLIDE_UP = 'slide-up'
      NAME_SLIDE_DOWN = 'slide-down'
      MODE_OUT_IN = ''
      MODE_IN_OUT = 'in-out'
  
      name = this.NAME_FADE
      mode = this.MODE_OUT_IN
  
      @Watch('$route', { immediate: true, deep: true })
      onRouteChanged(newVal: Route, oldVal: Route) {
        if (newVal.meta.transition === 'dialog') {
          this.name = this.NAME_SLIDE_UP
          this.mode = this.MODE_IN_OUT
  
        } else if (oldVal &amp;&amp; oldVal.meta.transition === 'dialog') {
          this.name = this.NAME_SLIDE_DOWN
          // shift next page in immediately below dialog
          this.mode = this.MODE_IN_OUT
  
        } else {
          // default
          this.name = this.NAME_FADE
          this.mode = this.MODE_OUT_IN
        }
      }
  
    }
  &lt;/script&gt;
  
  &lt;style lang=&quot;scss&quot; scoped&gt;
    .fade-enter, .fade-leave-to {
      opacity: 0;
    }
    .fade-enter-active, .fade-leave-active {
      transition: all 0.1s ease;
    }
  
  
    // start of enter element
    .slide-up-enter {
      transform: translateY(60%);
      opacity: 0;
    }
    .slide-up-enter-active {
      transition: all 0.3s ease-out;
      z-index: 2100;
    }
  
    // start of leave element
    .slide-up-leave, .slide-up-leave-active {
      opacity: 0;
    }
    
  
    // start of leave element
    .slide-down-leave {
      z-index: 2100;
    }
    .slide-down-leave-to {
      transform: translateY(60%);
      opacity: 0;
      z-index: 2100;
    }
    .slide-down-leave-active {
      transition: all 0.3s ease-in;
    }
  
    // start of enter element
    .slide-down-enter {
      opacity: 0;
    }
    .slide-down-enter-active {
      /* show immediately behind existing page (lower z-index) */
      transition: all 0s;
    }
  &lt;/style&gt;
  
  </code></pre>