Learn how to implement a versatile pop-up box in Laravel, designed to showcase custom images and text content on your website's frontend. A dedicated admin panel empowers administrators to easily modify the pop-up's appearance, including colors, size, content, and visibility status. This provides a code-free way for non-developers to manage website announcements or promotions directly.
This guide details how to build a dynamic pop-up box feature for a Laravel website. The pop-up is designed to display both images and text content to engage visitors upon landing on pages like the homepage. A key aspect is the deep customization managed through an easy-to-use admin panel. Administrators can modify the pop-up's image, text, colors (background and text), dimensions (width/height), and toggle its visibility without touching code. This allows non-developers to easily update website announcements, promotions, or alerts directly via the backend interface.
Create a customizable pop-up image box feature for your Laravel application.
This will involve:
Backend Setup (Laravel):
A Model and Migration for storing pop-up settings.
A Controller for managing these settings in the admin panel.
Routes for the admin panel and potentially fetching data for the frontend.
Admin Views for the form.
Frontend Setup:
A Blade component or partial for the pop-up structure.
CSS for styling (including dynamic styles).
JavaScript for controlling the pop-up visibility and behavior.
Step 1: Backend Setup (Laravel)
1.1. Create Model and Migration:
Open your terminal in your Laravel project directory and run:
Now, edit the generated migration file (database/migrations/YYYY_MM_DD_HHMMSS_create_popup_settings_table.php):
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('popup_settings', function (Blueprint $table) {
$table->id();
$table->string('image_path')->nullable(); // Path to the image
$table->text('text')->nullable(); // Pop-up text/content
$table->string('background_color')->default('#FFFFFF'); // Background color
$table->string('text_color')->default('#000000'); // Text color
$table->string('width')->default('500px'); // e.g., '500px', '80%'
$table->string('height')->default('auto'); // e.g., '300px', 'auto'
$table->boolean('is_active')->default(false); // Controls if the pop-up is shown
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('popup_settings');
}
};
Edit the Model (app/Models/PopupSetting.php) to allow mass assignment:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class PopupSetting extends Model
{
use HasFactory;
// Allow these fields to be mass-assigned
protected $fillable = [
'image_path',
'text',
'background_color',
'text_color',
'width',
'height',
'is_active',
];
// Cast boolean value correctly
protected $casts = [
'is_active' => 'boolean',
];
}
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\PopupSetting;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage; // <-- Import Storage facade
use Illuminate\Validation\Rule; // <-- Import Rule for validation
class PopupSettingController extends Controller
{
// We assume there's only one pop-up setting record needed for the site.
// We'll use ID 1, or create it if it doesn't exist.
/**
* Show the form for editing the specified resource.
*/
public function edit() // Simplified: Always edit the first record
{
// Find the first setting, or create a default one if none exists
$setting = PopupSetting::firstOrCreate(['id' => 1]);
return view('admin.popup.edit', compact('setting'));
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request) // Simplified: Always update the first record
{
$setting = PopupSetting::findOrFail(1); // Find setting with ID 1
$validated = $request->validate([
'image' => 'nullable|image|mimes:jpeg,png,jpg,gif,svg,webp|max:2048', // Max 2MB
'text' => 'nullable|string',
'background_color' => 'required|string|regex:/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$|^rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(,\s*(0|1|0?\.\d+))?\s*\)$/i', // Validate hex or rgba
'text_color' => 'required|string|regex:/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$|^rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(,\s*(0|1|0?\.\d+))?\s*\)$/i', // Validate hex or rgba
'width' => 'required|string|max:20', // e.g., '500px', '80%'
'height' => 'required|string|max:20', // e.g., '300px', 'auto'
'is_active' => 'sometimes|boolean', // 'sometimes' because checkbox might not be sent if unchecked
]);
// Handle image upload
if ($request->hasFile('image')) {
// Delete old image if it exists
if ($setting->image_path && Storage::disk('public')->exists($setting->image_path)) {
Storage::disk('public')->delete($setting->image_path);
}
// Store the new image in 'storage/app/public/popups'
$path = $request->file('image')->store('popups', 'public');
$validated['image_path'] = $path;
}
// Handle 'is_active' checkbox (if unchecked, it won't be in the request)
$validated['is_active'] = $request->has('is_active');
// Update the settings
$setting->update($validated);
return redirect()->route('admin.popup.edit')->with('success', 'Pop-up settings updated successfully!');
}
/**
* Optional: Method to remove the image
*/
public function removeImage()
{
$setting = PopupSetting::findOrFail(1);
if ($setting->image_path && Storage::disk('public')->exists($setting->image_path)) {
Storage::disk('public')->delete($setting->image_path);
$setting->image_path = null;
$setting->save();
return redirect()->route('admin.popup.edit')->with('success', 'Pop-up image removed successfully!');
}
return redirect()->route('admin.popup.edit')->with('error', 'No image to remove.');
}
}
Okay, let's create a customizable pop-up image box feature for your Laravel application.
This will involve:
Backend Setup (Laravel):
A Model and Migration for storing pop-up settings.
A Controller for managing these settings in the admin panel.
Routes for the admin panel and potentially fetching data for the frontend.
Admin Views for the form.
Frontend Setup:
A Blade component or partial for the pop-up structure.
CSS for styling (including dynamic styles).
JavaScript for controlling the pop-up visibility and behavior.
Step 1: Backend Setup (Laravel)
1.1. Create Model and Migration:
Open your terminal in your Laravel project directory and run:
<?phpnamespaceApp\Http\Controllers\Admin;
useApp\Http\Controllers\Controller;
useApp\Models\PopupSetting;
useIlluminate\Http\Request;
useIlluminate\Support\Facades\Storage; // <-- Import Storage facadeuseIlluminate\Validation\Rule; // <-- Import Rule for validationclassPopupSettingControllerextendsController{
// We assume there's only one pop-up setting record needed for the site.// We'll use ID 1, or create it if it doesn't exist./**
* Show the form for editing the specified resource.
*/publicfunctionedit() // Simplified: Alwayseditthefirstrecord{
// Find the first setting, or create a default one if none exists$setting = PopupSetting::firstOrCreate(['id' => 1]);
return view('admin.popup.edit', compact('setting'));
}
/**
* Update the specified resource in storage.
*/publicfunctionupdate(Request $request) // Simplified: Alwaysupdatethefirstrecord{
$setting = PopupSetting::findOrFail(1); // Find setting with ID 1$validated = $request->validate([
'image' => 'nullable|image|mimes:jpeg,png,jpg,gif,svg,webp|max:2048', // Max 2MB'text' => 'nullable|string',
'background_color' => 'required|string|regex:/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$|^rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(,\s*(0|1|0?\.\d+))?\s*\)$/i', // Validate hex or rgba'text_color' => 'required|string|regex:/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$|^rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(,\s*(0|1|0?\.\d+))?\s*\)$/i', // Validate hex or rgba'width' => 'required|string|max:20', // e.g., '500px', '80%''height' => 'required|string|max:20', // e.g., '300px', 'auto''is_active' => 'sometimes|boolean', // 'sometimes' because checkbox might not be sent if unchecked
]);
// Handle image uploadif ($request->hasFile('image')) {
// Delete old image if it existsif ($setting->image_path && Storage::disk('public')->exists($setting->image_path)) {
Storage::disk('public')->delete($setting->image_path);
}
// Store the new image in 'storage/app/public/popups'$path = $request->file('image')->store('popups', 'public');
$validated['image_path'] = $path;
}
// Handle 'is_active' checkbox (if unchecked, it won't be in the request)$validated['is_active'] = $request->has('is_active');
// Update the settings$setting->update($validated);
return redirect()->route('admin.popup.edit')->with('success', 'Pop-up settings updated successfully!');
}
/**
* Optional: Method to remove the image
*/publicfunctionremoveImage()
{
$setting = PopupSetting::findOrFail(1);
if ($setting->image_path && Storage::disk('public')->exists($setting->image_path)) {
Storage::disk('public')->delete($setting->image_path);
$setting->image_path = null;
$setting->save();
return redirect()->route('admin.popup.edit')->with('success', 'Pop-up image removed successfully!');
}
return redirect()->route('admin.popup.edit')->with('error', 'No image to remove.');
}
}
1.3. Define Admin Routes:
Add these routes to your routes/web.php file, preferably within an admin middleware group:
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Admin\PopupSettingController;
use App\Http\Controllers\HomeController; // Or your relevant controller
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
*/
// Homepage Route (Example) - Fetch popup settings here
Route::get('/', [HomeController::class, 'index'])->name('homepage');
// Admin Routes (Example - adjust middleware as needed)
Route::middleware(['auth', 'admin'])->prefix('admin')->name('admin.')->group(function () {
// Other admin routes...
// Pop-up Settings Routes
Route::get('/popup-settings', [PopupSettingController::class, 'edit'])->name('popup.edit');
Route::put('/popup-settings', [PopupSettingController::class, 'update'])->name('popup.update');
Route::delete('/popup-settings/image', [PopupSettingController::class, 'removeImage'])->name('popup.removeImage'); // Route to remove image
});
// Add Auth routes if you don't have them
// Auth::routes(); // Example if using laravel/ui
Okay, let's create a customizable pop-up image box feature for your Laravel application.
This will involve:
Backend Setup (Laravel):
A Model and Migration for storing pop-up settings.
A Controller for managing these settings in the admin panel.
Routes for the admin panel and potentially fetching data for the frontend.
Admin Views for the form.
Frontend Setup:
A Blade component or partial for the pop-up structure.
CSS for styling (including dynamic styles).
JavaScript for controlling the pop-up visibility and behavior.
Step 1: Backend Setup (Laravel)
1.1. Create Model and Migration:
Open your terminal in your Laravel project directory and run:
<?phpnamespaceApp\Http\Controllers\Admin;
useApp\Http\Controllers\Controller;
useApp\Models\PopupSetting;
useIlluminate\Http\Request;
useIlluminate\Support\Facades\Storage; // <-- Import Storage facadeuseIlluminate\Validation\Rule; // <-- Import Rule for validationclassPopupSettingControllerextendsController{
// We assume there's only one pop-up setting record needed for the site.// We'll use ID 1, or create it if it doesn't exist./**
* Show the form for editing the specified resource.
*/publicfunctionedit() // Simplified: Alwayseditthefirstrecord{
// Find the first setting, or create a default one if none exists$setting = PopupSetting::firstOrCreate(['id' => 1]);
return view('admin.popup.edit', compact('setting'));
}
/**
* Update the specified resource in storage.
*/publicfunctionupdate(Request $request) // Simplified: Alwaysupdatethefirstrecord{
$setting = PopupSetting::findOrFail(1); // Find setting with ID 1$validated = $request->validate([
'image' => 'nullable|image|mimes:jpeg,png,jpg,gif,svg,webp|max:2048', // Max 2MB'text' => 'nullable|string',
'background_color' => 'required|string|regex:/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$|^rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(,\s*(0|1|0?\.\d+))?\s*\)$/i', // Validate hex or rgba'text_color' => 'required|string|regex:/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$|^rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(,\s*(0|1|0?\.\d+))?\s*\)$/i', // Validate hex or rgba'width' => 'required|string|max:20', // e.g., '500px', '80%''height' => 'required|string|max:20', // e.g., '300px', 'auto''is_active' => 'sometimes|boolean', // 'sometimes' because checkbox might not be sent if unchecked
]);
// Handle image uploadif ($request->hasFile('image')) {
// Delete old image if it existsif ($setting->image_path && Storage::disk('public')->exists($setting->image_path)) {
Storage::disk('public')->delete($setting->image_path);
}
// Store the new image in 'storage/app/public/popups'$path = $request->file('image')->store('popups', 'public');
$validated['image_path'] = $path;
}
// Handle 'is_active' checkbox (if unchecked, it won't be in the request)$validated['is_active'] = $request->has('is_active');
// Update the settings$setting->update($validated);
return redirect()->route('admin.popup.edit')->with('success', 'Pop-up settings updated successfully!');
}
/**
* Optional: Method to remove the image
*/publicfunctionremoveImage()
{
$setting = PopupSetting::findOrFail(1);
if ($setting->image_path && Storage::disk('public')->exists($setting->image_path)) {
Storage::disk('public')->delete($setting->image_path);
$setting->image_path = null;
$setting->save();
return redirect()->route('admin.popup.edit')->with('success', 'Pop-up image removed successfully!');
}
return redirect()->route('admin.popup.edit')->with('error', 'No image to remove.');
}
}
1.3. Define Admin Routes:
Add these routes to your routes/web.php file, preferably within an admin middleware group:
PHP
<?phpuseIlluminate\Support\Facades\Route;
useApp\Http\Controllers\Admin\PopupSettingController;
useApp\Http\Controllers\HomeController; // Or your relevant controller/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
*/// Homepage Route (Example) - Fetch popup settings here
Route::get('/', [HomeController::class, 'index'])->name('homepage');
// Admin Routes (Example - adjust middleware as needed)
Route::middleware(['auth', 'admin'])->prefix('admin')->name('admin.')->group(function () {
// Other admin routes...// Pop-up Settings Routes
Route::get('/popup-settings', [PopupSettingController::class, 'edit'])->name('popup.edit');
Route::put('/popup-settings', [PopupSettingController::class, 'update'])->name('popup.update');
Route::delete('/popup-settings/image', [PopupSettingController::class, 'removeImage'])->name('popup.removeImage'); // Route to remove image
});
// Add Auth routes if you don't have them// Auth::routes(); // Example if using laravel/ui
1.4. Create Admin View:
Create the directory resources/views/admin/popup. Create the file resources/views/admin/popup/edit.blade.php.
Make sure your storage is linked so public files are accessible via URL. If you haven't done this before, run:
Bash
php artisan storage:link
This creates a symbolic link from public/storage to storage/app/public.
Step 2: Frontend Setup
2.1. Fetch Data in Homepage Controller:
Modify your HomeController (or wherever your homepage logic resides) to fetch the active pop-up setting.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\PopupSetting; // <-- Import the model
class HomeController extends Controller
{
/**
* Show the application dashboard.
*
* @return \Illuminate\Contracts\Support\Renderable
*/
public function index()
{
// Fetch the *first* active pop-up setting
$popupSetting = PopupSetting::where('is_active', true)->first();
// Pass the setting (or null) to the view
return view('welcome', compact('popupSetting')); // Adjust 'welcome' to your homepage view name
}
}
2.2. Create Pop-up Blade View/Component:
Create a file like resources/views/components/popup.blade.php (or resources/views/partials/popup.blade.php).
In your main homepage Blade file (e.g., resources/views/welcome.blade.php), include the component/partial, passing the data from the controller:
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Website</title>
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="{{ asset('css/popup.css') }}">
{{-- Your other CSS --}}
@vite(['resources/css/app.css', 'resources/js/app.js']) {{-- Example if using Vite --}}
</head>
<body class="antialiased">
{{-- Your main homepage content here --}}
<h1>Welcome to the Homepage!</h1>
<p>This is the main content of the page.</p>
{{-- Include the Pop-up Component --}}
{{-- Pass the $popupSetting variable fetched in the controller --}}
<x-popup :setting="$popupSetting" />
{{-- OR if using a partial: @include('partials.popup', ['setting' => $popupSetting]) --}}
{{-- Include Pop-up JS (before closing body tag is best) --}}
<script src="{{ asset('js/popup.js') }}"></script>
{{-- Your other JS --}}
</body>
</html>
2.4. Create CSS File:
Create public/css/popup.css:
/* Pop-up Overlay */
.popup-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.6); /* Semi-transparent black background */
display: flex;
justify-content: center;
align-items: center;
z-index: 1000; /* Make sure it's on top */
opacity: 1;
visibility: visible;
transition: opacity 0.3s ease, visibility 0s linear 0s; /* Smooth fade in */
}
.popup-overlay.hidden {
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0s linear 0.3s; /* Smooth fade out */
}
/* Pop-up Box */
.popup-box {
position: relative; /* Needed for absolute positioning of the close button */
padding: 35px 25px 25px 25px; /* Add padding, more top padding for close button */
border-radius: 8px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
transform: scale(1);
transition: transform 0.3s ease;
/* Dynamic styles (width, height, background-color, color) are applied inline */
display: flex; /* Use flexbox for layout */
flex-direction: column; /* Stack content vertically */
}
/* Animate pop-up box appearance */
.popup-overlay.hidden .popup-box {
transform: scale(0.9);
}
/* Close Button */
.popup-close {
position: absolute;
top: 8px;
right: 10px;
background: none;
border: none;
font-size: 28px; /* Make it larger */
font-weight: bold;
color: inherit; /* Inherit color from popup-box text_color */
opacity: 0.7;
cursor: pointer;
line-height: 1;
padding: 0;
}
.popup-close:hover {
opacity: 1;
}
/* Content Area */
.popup-content {
/* Allow content to grow if needed */
flex-grow: 1;
/* For potential scrolling within content if needed, often handled by popup-box */
/* overflow-y: auto; */
}
.popup-image-container {
text-align: center; /* Center image if it's smaller than container */
margin-bottom: 15px;
}
.popup-image {
max-width: 100%; /* Ensure image is responsive */
height: auto; /* Maintain aspect ratio */
max-height: 60vh; /* Limit image height */
display: block; /* Prevents bottom space */
margin: 0 auto; /* Center block image */
}
.popup-text {
line-height: 1.6;
font-size: 1rem;
/* Text color is inherited from .popup-box */
}
/* Add some basic responsive adjustments */
@media (max-width: 600px) {
.popup-box {
padding: 30px 15px 15px 15px;
/* Width/height handled by inline styles and max-width/max-height */
}
.popup-close {
font-size: 24px;
top: 5px;
right: 8px;
}
}
2.5. Create JavaScript File:
Create public/js/popup.js:
document.addEventListener('DOMContentLoaded', function() {
const popupOverlay = document.getElementById('customPopupOverlay');
const closeButton = document.getElementById('customPopupClose');
const popupBox = document.getElementById('customPopupBox');
// Check if the popup elements exist on the page
if (!popupOverlay || !closeButton || !popupBox) {
// console.log('Popup elements not found.');
return; // Exit if popup isn't rendered
}
// Function to close the popup
function closePopup() {
popupOverlay.classList.add('hidden');
// Optional: Store in sessionStorage to prevent showing again in the same session
try {
sessionStorage.setItem('popupShown', 'true');
} catch (e) {
console.error('Session storage is unavailable.', e);
}
}
// Function to open the popup
function openPopup() {
// Optional: Check if popup was already shown in this session
try {
if (sessionStorage.getItem('popupShown') === 'true') {
console.log('Popup already shown this session.');
popupOverlay.classList.add('hidden'); // Ensure it's hidden if already shown
popupOverlay.style.display = 'none'; // Prevent flash of content
return;
}
} catch (e) {
console.error('Session storage is unavailable.', e);
}
popupOverlay.classList.remove('hidden');
}
// Event listener for the close button
closeButton.addEventListener('click', closePopup);
// Event listener to close when clicking the overlay (outside the box)
popupOverlay.addEventListener('click', function(event) {
// Check if the click was directly on the overlay, not on the box itself
if (event.target === popupOverlay) {
closePopup();
}
});
// Event listener for the 'Escape' key
document.addEventListener('keydown', function(event) {
if (event.key === 'Escape' && !popupOverlay.classList.contains('hidden')) {
closePopup();
}
});
// --- Initially open the popup (after checking session storage) ---
openPopup();
});
How to Use:
Run php artisan migrate.
Run php artisan storage:link (if you haven't already).
Log in to your admin panel.
Navigate to /admin/popup-settings (or the route you defined).
Fill in the form:
Upload an image (optional).
Add text (optional).
Choose background and text colors.
Set the desired width and height (use CSS units like px or %). auto is valid for height.
Check the "Show Pop-up on Homepage?" box to activate it.
Save settings.
Visit your homepage (/). The pop-up should appear if it's active and configured.
The pop-up should only appear once per browser session due to the sessionStorage implementation in the JavaScript. Clear your session storage or close/reopen the browser tab/window to see it again for testing.
This provides a robust and customizable pop-up solution integrated into your Laravel admin panel. Remember to adjust layout names (layouts.admin, welcome.blade.php), route middleware ('auth', 'admin'), and potentially CSS/JS paths based on your specific project setup (e.g., if using Vite, ensure CSS/JS are correctly bundled and referenced).
Learn to build an interactive EMI calculator in Laravel! This [2025] step-by-step guide provides full code using Bootstrap, JavaScript, Chart.js, and includes an amortization schedule.
This code creates a user-friendly contact form with HTML. CSS styles the form for a clean, modern aesthetic. It includes fields for name, email, subject, and message. The form is designed for easy data collection and submission.