In this article, we will be discussing how to create dynamic pop-up modals in Laravel, Vue, Inertia, and Vite using the Teleport feature. This tutorial is designed for entry-level users, so no prior experience with these technologies is required.
Prerequisites
Before we begin, you should have the following tools installed:
- PHP 7.3.0 or higher
- Composer
- Node.js and npm
- A code editor such as Visual Studio Code
Setting up the project
To start, we will create a new Laravel project using Composer. Open a terminal and run the following command:
composer create-project --prefer-dist laravel/laravel dynamic-modals
Next, navigate to the project directory and install the dependencies:
cd dynamic-modals
composer install
Now, we will install Inertia, Vue, and Vite. Run the following commands:
composer require inertiajs/inertia-laravel
npm install @inertiajs/inertia @inertiajs/inertia-vue3 vite laravel-vite-plugin
To configure Laravel to use Inertia, open the app/Providers/AppServiceProvider.php file and add the following code to the boot() method:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
Inertia::setRootView('app');
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Inertia::version(function () {
return md5_file(public_path('mix-manifest.json'));
});
}
}
To configure Vite, open the webpack.mix.js file and add the following code:
const mix = require('laravel-mix');
const { createVue } = require('laravel-vite-plugin/utils');
mix.js('resources/js/app.js', 'public/js')
.vue()
.postCss('resources/css/app.css', 'public/css', [
require('postcss-import'),
require('tailwindcss'),
require('autoprefixer'),
]);
mix.browserSync('dynamic-modals.test');
if (mix.inProduction()) {
mix.version();
}
mix.webpackConfig({
plugins: [
createVue({
'config': {
'devServer': {
'client': {
'progress': true,
'overlay': {
'errors': true,
'warnings': true,
},
},
},
},
}),
],
});
Creating the pop-up modal
Now that we have our project set up, we can create the pop-up modal. First, we will create a new Vue component. In the resources/js/components directory, create a new file called Modal.vue and add the following code:
<template>
<div
v-if="isOpen"
class="fixed z-10 inset-0 overflow-y-auto"
aria-labelledby="modal-title"
role="dialog"
aria-modal="true"
>
<div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"
>
<div
class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity"
aria-hidden="true"
></div>
<span
class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true"
></span><div
class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
>
<div
class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"
>
<div
class="sm:flex sm:items-start"
>
<div
class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"
>
<h3
class="text-lg leading-6 font-medium text-gray-900"
id="modal-title"
>
{{ title }}
</h3>
<div
class="mt-2"
>
<p
class="text-sm text-gray-500"
>
{{ content }}
</p>
</div>
</div>
</div>
<div
class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"
>
<button
@click="close"
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm"
>
Close
</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
isOpen: false,
title: '',
content: '',
};
},
methods: {
open(title, content) {
this.isOpen = true;
this.title = title;
this.content = content;
},
close() {
this.isOpen = false;
},
},
};
</script>
Now, we can use this component in our Laravel views. In the resources/js/pages/Welcome.vue file, add the following code:
<template>
<div class="relative sm:flex sm:justify-center sm:items-center min-h-screen">
<div class="absolute inset-0 bg-gray-500 opacity-75"></div>
<div class="relative flex-1 text-center sm:flex sm:items-center sm:text-left">
<div class="absolute inset-0 sm:static bg-white sm:bg-transparent sm:b-0 sm:left-0 sm:right-0 sm:shadow-none">
<div class="max-w-7xl w-full lg:w-5/6 mx-auto sm:px-6 lg:px-8">
<div class="bg-white px-4 pt-16 pb-20 text-center sm:px-6 sm:pt-20 sm:pb-24 lg:px-8 lg:pt-24 lg:pb-28">
<h2
class="text-3xl leading-9 tracking-tight font-extrabold text-gray-900 sm:text-4xl sm:leading-10"
>
Welcome to your new app!
</h2>
<p
class="text-xl leading-7 text-gray-500 mt-5 sm:text-2xl sm:leading-9"
>
Laravel v{{ lumenVersion() }}
PHP v{{ phpversion() }}
</p>
<div class="mt-10">
<button
@click="openModal"
type="button"
class="inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:text-sm"
>
Open Modal
</button>
</div>
</div>
</div>
</div>
<modal :title="modalTitle" :content="modalContent" />
</div>
</div>
</template>
<script>
import Modal from './components/Modal.vue';
export default {
components: {
Modal,
},
data() {
return {
modalTitle: '',
modalContent: '',
};
},
methods: {
openModal() {
this.modalTitle = 'Modal Title';
this.modalContent = 'Modal Content';
this.modal = true;
},
},
};
</script>
Now, when you run the application, you will see a button that opens the pop-up modal. The modal is created using the Modal.vue component, which is imported at the top of the file. The openModal() method sets the title and content of the modal, which are then displayed in the modal component.
Using Teleport
The pop-up modal we created is static, meaning it is always present in the DOM. However, we can use the Teleport component to dynamically insert the modal into the DOM. This can be useful if you have a large number of modals, as it will keep the DOM clean and prevent performance issues.
To use the Teleport component, we will make a small change to the Modal.vue component. Change the template section to the following:
<template>
<teleport
to="body"
>
<div
v-if="isOpen"
class="fixed z-10 inset-0 overflow-y-auto"
aria-labelledby="modal-title"
role="dialog"
aria-modal="true"
>
<div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"
>
<div
class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity"
aria-hidden="true"
></div>
<span
class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true"
></span><div
class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
>
<div
class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"
>
<div
class="sm:flex sm:items-start"
>
<div
class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"
>
<h3
class="text-lg leading-6 font-medium text-gray-900"
id="modal-title"
>
{{ title }}
</h3>
<div
class="mt-2"
>
<p
class="text-sm text-gray-500"
>
{{ content }}
</p>
</div>
</div>
</div>
<div
class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"
>
<button
@click="close"
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm"
>
Close
</button>
</div>
</div>
</div>
</div>
</teleport>
</template>
Now, when the modal is opened, it will be inserted into the DOM at the end of the body element. This will keep the DOM clean and prevent any performance issues.
In this article, we have discussed how to create dynamic pop-up modals in Laravel, Vue, Inertia, and Vite using the Teleport feature. We have also covered how to use the Teleport component to dynamically insert the modal into the DOM. This tutorial is designed for entry-level users, so no prior experience with these technologies is required. We hope you have found this article helpful and informative. Happy coding!
References
| Title | URL |
|---|---|
| Laravel documentation | https://laravel.com/docs/8.x |
| Inertia documentation | https://inertiajs.com/server-side-components |
| Vue documentation | https://vuejs.org/v2/guide/ |
| Vite documentation | https://vitejs.dev/guide/ |
| Teleport documentation | https://v2.vuejs.org/v2/api/#teleport |