Lara Blade

Elements

Modals

When your browser decides to play peek-a-boo with information.

Contributors for this component
<x-lb.element.modal> <x-slot name="trigger"> <x-lb.element.button.primary> Open Modal </x-lb.element.button.primary> </x-slot> <x-lb.element.modal.panel> <x-lb.element.modal.close /> <x-lb.element.modal.header> Modal title </x-lb.element.modal.header> <x-lb.element.modal.body> <p>Modal content</p> </x-lb.element.modal.body> <x-lb.element.modal.footer> <x-lb.element.button.text> Close </x-lb.element.button.text> <x-lb.element.button.primary> Save </x-lb.element.button.primary> </x-lb.element.modal.footer> </x-lb.element.modal.panel> </x-lb.element.modal>

Regular Modal Example

<div class="grid grid-cols-1 md:grid-cols-3 gap-4"> <x-lb.element.modal full="true"> <x-slot name="trigger"> <x-lb.element.button.primary> Open from Bottom </x-lb.element.button.primary> </x-slot> <x-lb.element.modal.panel-full transition="bottom"> <x-lb.element.modal.close class="bg-white sm:p-4" /> <div class="h-full w-full bg-center bg-cover bg-neutral-800" style="background-image: url('/images/resources/Taieri.svg')"> </div> </x-lb.element.modal.panel-full> </x-lb.element.modal> <x-lb.element.modal full="true"> <x-slot name="trigger"> <x-lb.element.button.primary> Open from Middle </x-lb.element.button.primary> </x-slot> <x-lb.element.modal.panel-full transition="middle"> <x-lb.element.modal.close class="bg-white sm:p-4" /> <div class="h-full w-full bg-center bg-cover bg-neutral-800" style="background-image: url('/images/resources/Taieri.svg')"> </div> </x-lb.element.modal.panel-full> </x-lb.element.modal> <x-lb.element.modal full="true"> <x-slot name="trigger"> <x-lb.element.button.primary> Open from Top </x-lb.element.button.primary> </x-slot> <x-lb.element.modal.panel-full transition="top"> <x-lb.element.modal.close class="bg-white sm:p-4" /> <div class="h-full w-full bg-center bg-cover bg-neutral-800" style="background-image: url('/images/resources/Taieri.svg')"> </div> </x-lb.element.modal.panel-full> </x-lb.element.modal> </div>

Full Screen Modal Example

Data and Props

Propreties and props that are avaiable for this component

slot
Allows for dynamic inner content to be provided when the component is used.
modal
set the x-data value that will be used instead of openModal
width
set the max width of the modal
rounded
set the corner radious
transition
choose animation for full screen modal
@props([ 'full' => false, 'data' => 'modalOpen', ]) <div x-data="{ '{{ $data }}': false }" @keydown.escape.window="$dispatch('close-modal')" x-on:close-modal.window="{{ $data }} = false" x-init="if ('{{ $full }}') { $watch('modalOpen', function(value) { if (value === true) { document.body.classList.add('overflow-hidden'); } else { document.body.classList.remove('overflow-hidden'); } }) }"> @isset($trigger) <div @click="modalOpen=true" class="cursor-pointer"> {{ $trigger }} </div> @endisset {{ $slot }} </div>

modal.index

@props([
'full' => false,
'data' => 'modalOpen',
])
 
<div x-data="{ '{{ $data }}': false }" @keydown.escape.window="$dispatch('close-modal')"
x-on:close-modal.window="{{ $data }} = false" x-init="if ('{{ $full }}') {
$watch('modalOpen', function(value) {
if (value === true) {
document.body.classList.add('overflow-hidden');
} else {
document.body.classList.remove('overflow-hidden');
}
})
}">
 
@isset($trigger)
<div @click="modalOpen=true" class="cursor-pointer">
{{ $trigger }}
</div>
@endisset
 
{{ $slot }}
</div>
@props([ 'width' => 'lg', 'rounded' => 'lg', 'custom' => '', 'modal', ]) @php $maxWidthClass = ' sm:max-w-' . $width; $roundedClass = ' sm:rounded-' . $rounded; $classes = ' ' . $maxWidthClass . $roundedClass . ' ' . $custom; @endphp <template x-teleport="body"> <div x-show="{{ $modal ?? 'modalOpen' }}" class="fixed top-0 left-0 z-[99] flex items-center justify-center w-screen h-screen" style="display:none"> <div x-show="{{ $modal ?? 'modalOpen' }}" x-transition:enter="ease-out duration-300" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" x-transition:leave="ease-in duration-300" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0" @click="$dispatch('close-modal')" class="absolute inset-0 w-full h-full bg-black bg-opacity-40"></div> <div x-show="{{ $modal ?? 'modalOpen' }}" x-trap.inert.noscroll="{{ $modal ?? 'modalOpen' }}" x-transition:enter="ease-out duration-300" x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100" x-transition:leave="ease-in duration-200" x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100" x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" class="relative w-full bg-white {{ $classes }} flex flex-col justify-between overflow-y-auto scrollbar-active"> {{ $slot }} </div> </div> </template>

modal.panel

@props([
'width' => 'lg',
'rounded' => 'lg',
'custom' => '',
'modal',
])
 
@php
$maxWidthClass = ' sm:max-w-' . $width;
 
$roundedClass = ' sm:rounded-' . $rounded;
$classes = ' ' . $maxWidthClass . $roundedClass . ' ' . $custom;
@endphp
 
<template x-teleport="body">
<div x-show="{{ $modal ?? 'modalOpen' }}"
class="fixed top-0 left-0 z-[99] flex items-center justify-center w-screen h-screen" style="display:none">
<div x-show="{{ $modal ?? 'modalOpen' }}" x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100"
x-transition:leave="ease-in duration-300" x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0" @click="$dispatch('close-modal')"
class="absolute inset-0 w-full h-full bg-black bg-opacity-40"></div>
<div x-show="{{ $modal ?? 'modalOpen' }}" x-trap.inert.noscroll="{{ $modal ?? 'modalOpen' }}"
x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100" x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
class="relative w-full bg-white {{ $classes }} flex flex-col justify-between overflow-y-auto scrollbar-active">
{{ $slot }}
</div>
</div>
</template>
@props(['modal', 'transition' => 'bottom']) @php $transitions = [ 'bottom' => [ 'enter' => 'transition ease-out duration-500 sm:duration-700', 'enter-start' => 'translate-y-full', 'enter-end' => 'translate-y-0', 'leave' => 'transition ease-in duration-500 sm:duration-700', 'leave-start' => 'translate-y-0', 'leave-end' => 'translate-y-full', ], 'top' => [ 'enter' => 'transition ease-out duration-500 sm:duration-700', 'enter-start' => '-translate-y-full', 'enter-end' => 'translate-y-0', 'leave' => 'transition ease-in duration-500 sm:duration-700', 'leave-start' => 'translate-y-0', 'leave-end' => '-translate-y-full', ], 'middle' => [ 'enter' => 'ease-out duration-500 sm:duration-700', 'enter-start' => 'opacity-0', 'enter-end' => 'opacity-100', 'leave' => 'ease-in duration-500 sm:duration-700', 'leave-start' => 'opacity-100', 'leave-end' => 'opacity-0', ], ]; @endphp <template x-teleport="body"> <div x-show="{{ $modal ?? 'modalOpen' }}" x-transition:enter="{{ $transitions[$transition]['enter'] }}" x-transition:enter-start="{{ $transitions[$transition]['enter-start'] }}" x-transition:enter-end="{{ $transitions[$transition]['enter-end'] }}" x-transition:leave="{{ $transitions[$transition]['leave'] }}" x-transition:leave-start="{{ $transitions[$transition]['leave-start'] }}" x-transition:leave-end="{{ $transitions[$transition]['leave-end'] }}" class="flex fixed inset-0 z-[99] w-screen h-screen bg-white" style="display:none"> {{ $slot }} </div> </template>

modal.panel-full

@props(['modal', 'transition' => 'bottom'])
 
@php
$transitions = [
'bottom' => [
'enter' => 'transition ease-out duration-500 sm:duration-700',
'enter-start' => 'translate-y-full',
'enter-end' => 'translate-y-0',
'leave' => 'transition ease-in duration-500 sm:duration-700',
'leave-start' => 'translate-y-0',
'leave-end' => 'translate-y-full',
],
'top' => [
'enter' => 'transition ease-out duration-500 sm:duration-700',
'enter-start' => '-translate-y-full',
'enter-end' => 'translate-y-0',
'leave' => 'transition ease-in duration-500 sm:duration-700',
'leave-start' => 'translate-y-0',
'leave-end' => '-translate-y-full',
],
'middle' => [
'enter' => 'ease-out duration-500 sm:duration-700',
'enter-start' => 'opacity-0',
'enter-end' => 'opacity-100',
'leave' => 'ease-in duration-500 sm:duration-700',
'leave-start' => 'opacity-100',
'leave-end' => 'opacity-0',
],
];
@endphp
 
<template x-teleport="body">
<div x-show="{{ $modal ?? 'modalOpen' }}" x-transition:enter="{{ $transitions[$transition]['enter'] }}"
x-transition:enter-start="{{ $transitions[$transition]['enter-start'] }}"
x-transition:enter-end="{{ $transitions[$transition]['enter-end'] }}"
x-transition:leave="{{ $transitions[$transition]['leave'] }}"
x-transition:leave-start="{{ $transitions[$transition]['leave-start'] }}"
x-transition:leave-end="{{ $transitions[$transition]['leave-end'] }}"
class="flex fixed inset-0 z-[99] w-screen h-screen bg-white" style="display:none">
{{ $slot }}
</div>
</template>
<h2 x-dialog:title {{ $attributes->merge(['class' => 'text-xl font-bold py-4 px-4 text-neutral-800']) }}> {{ $slot }} </h2>

modal.header

<h2 x-dialog:title {{ $attributes->merge(['class' => 'text-xl font-bold py-4 px-4 text-neutral-800']) }}>
{{ $slot }}
</h2>
@php $classes = 'absolute top-4 right-4 group cursor-pointer rounded-lg p-2 text-neutral-500 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 hover:bg-neutral-100 hover:text-primary-500 transition-all'; @endphp <div class="absolute top-4 right-4 group"> <div @click="$dispatch('close-modal')" {{ $attributes->merge(['class' => $classes]) }}> <span class="sr-only">Close modal</span> <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 group-hover:scale-150" viewBox="0 0 20 20" fill="currentColor"> <path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" /> </svg> </div> </div>

modal.close

@php
$classes = 'absolute top-4 right-4 group cursor-pointer rounded-lg p-2 text-neutral-500 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 hover:bg-neutral-100 hover:text-primary-500 transition-all';
@endphp
 
<div class="absolute top-4 right-4 group">
<div @click="$dispatch('close-modal')" {{ $attributes->merge(['class' => $classes]) }}>
<span class="sr-only">Close modal</span>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 group-hover:scale-150" viewBox="0 0 20 20"
fill="currentColor">
<path fill-rule="evenodd"
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
clip-rule="evenodd" />
</svg>
</div>
</div>
<div {{ $attributes->merge(['class' => 'p-4']) }}> {{ $slot }} </div>

modal.body

<div {{ $attributes->merge(['class' => 'p-4']) }}>
{{ $slot }}
</div>
<div @click="$dispatch('close-modal')" {{ $attributes->merge(['class' => 'p-4 flex space-x-2 justify-end bg-neutral-100 items-baseline sm:rounded-b-lg']) }}> {{ $slot }} </div>

modal.footer

<div @click="$dispatch('close-modal')"
{{ $attributes->merge(['class' => 'p-4 flex space-x-2 justify-end bg-neutral-100 items-baseline sm:rounded-b-lg']) }}>
{{ $slot }}
</div>