Skip to content
On this page

Modals

Modals are a specific use case of fragments and they are quite easy to use.

Definition

In order to use (stacked) modals, you should load a custom layout and also define the modal fragment as stacked. You don't need to call it modal, you can also choose any other name but just keep it consistent. You could even have multiple stacked fragments if required.

typescript
import Layout from './Layout.vue'
import { createNavigareApp } from '@navigare/vue3'
import { createApp as createVueApp, h } from 'vue'

export default createNavigareApp({
  setup({ Root, props }) {
    // Create Vue app with Navigare component as root component
    const app = createVueApp({
      render: () => {
        return h(Root, props, {
          default: ({ layout }) => h(Layout, { layout }),
        })
      },
    })

    return app
  },

  fragments: {
    modal: {
      stacked: true,
    },
  },
})

Layout

Once defined as stacked, you can render these in the layout.

vue
<template>
  <div>
    <navigare-fragments name="default" />

    <navigare-fragments
      name="modal"
      #default="{ fragments }"
    >
      <div
        class="fixed inset-0 flex items-center justify-center overflow-hidden transition-all"
        :class="{
          'pointer-events-none': fragments.length === 0,
          'bg-black/50': fragments.length > 0,
        }"
      >
        <transition-group name="slide-bottom">
          <template
            v-for="(fragment, index) in fragments"
            :key="index"
          >
            <component
              :is="fragment.component"
              :class="{
                'scale-75': index < fragments.length - 1,
              }"
            />
          </template>
        </transition-group>
      </div>
    </navigare-fragments>
  </div>
</template>

<script lang="ts" setup>
import { NavigareFragments } from '@navigare/vue3'

defineProps({
  layout: String,
})
</script>

<style>
.slide-bottom-enter-active,
.slide-bottom-leave-active {
  transition: all 200ms ease-out;

  & > div {
    transition: all 200ms ease-out;
  }
}

.slide-bottom-enter-from,
.slide-bottom-leave-to {
  opacity: 0;

  & > div {
    transform: translateY(20%);
  }
}
</style>

The previous example uses Vue transitions to nicely animate these modals. You could also use <navigare-fragments name="modal" /> to render these plain one after the other.

Response

Eventually, you just need to respond with the modal fragment (see fragments). Optionally, you can define a route that will be visible in the background via extends.

php
<?php

namespace App\Http\Controllers;

use Navigare\Navigare;

class ContactsController
{
  public function index()
  {
    return Navigare::render('contacts/Index', []);
  }

  public function create()
  {
    return Navigare::modal('contacts/Create', [
      'organizations' => Auth::user()
        ->account->organizations()
        ->orderBy('name')
        ->get()
        ->map->only('id', 'name'),
    ])->extends(route('contacts.index'));
  }
}