Tailwind CSS and Alpine JS Modal
Modals are an excellent way to provide additional information or features to your users without disrupting their current workflow.
This component requires Alpine JS v3 to function properly. Some advanced features may require additional Alpine plugins (such as focus).
Tell Me MoreDefault Modal
A modal with a title, description, and two action buttons. On smaller screens, the modal dialog will position itself at the bottom, ensuring easy access to the buttons.
Special Offer
As a token of appreciation, we have an exclusive offer just for you. Upgrade your account now to unlock premium features and enjoy a seamless experience.
<div x-data="{modalIsOpen: false}">
<button @click="modalIsOpen = true" type="button" class="">Open Modal</button>
<div x-cloak x-show="modalIsOpen" x-transition.opacity.duration.200ms x-trap.inert.noscroll="modalIsOpen" @keydown.esc.window="modalIsOpen = false" @click.self="modalIsOpen = false" class="" role="dialog" aria-modal="true" aria-labelledby="defaultModalTitle">
<!-- Modal Dialog -->
<div x-show="modalIsOpen" x-transition:enter="transition ease-out duration-200 delay-100 motion-reduce:transition-opacity" x-transition:enter-start="opacity-0 scale-50" x-transition:enter-end="opacity-100 scale-100" class="">
<!-- Dialog Header -->
<div class="">
<h3 id="defaultModalTitle" class="">Special Offer</h3>
<button @click="modalIsOpen = false" aria-label="close modal">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" stroke="currentColor" fill="none" stroke-width="1.4" class="w-5 h-5">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
<!-- Dialog Body -->
<div class="">
<p>As a token of appreciation, we have an exclusive offer just for you. Upgrade your account now to unlock premium features and enjoy a seamless experience.</p>
</div>
<!-- Dialog Footer -->
<div class="">
<button @click="modalIsOpen = false" type="button" class="">Remind me later</button>
<button @click="modalIsOpen = false" type="button" class="">Upgrade Now</button>
</div>
</div>
</div>
</div>
Modal Transition
An example of a default modal with various transition options.
Special Offer
As a token of appreciation, we have an exclusive offer just for you. Upgrade your account now to unlock premium features and enjoy a seamless experience.
Special Offer
As a token of appreciation, we have an exclusive offer just for you. Upgrade your account now to unlock premium features and enjoy a seamless experience.
Special Offer
As a token of appreciation, we have an exclusive offer just for you. Upgrade your account now to unlock premium features and enjoy a seamless experience.
Special Offer
As a token of appreciation, we have an exclusive offer just for you. Upgrade your account now to unlock premium features and enjoy a seamless experience.
Special Offer
As a token of appreciation, we have an exclusive offer just for you. Upgrade your account now to unlock premium features and enjoy a seamless experience.
Special Offer
As a token of appreciation, we have an exclusive offer just for you. Upgrade your account now to unlock premium features and enjoy a seamless experience.
<div x-data="{modalIsOpen: false}">
<button @click="modalIsOpen = true" type="button" class="">Open Modal</button>
<div x-cloak x-show="modalIsOpen" x-transition.opacity.duration.200ms x-trap.inert.noscroll="modalIsOpen" @keydown.esc.window="modalIsOpen = false" @click.self="modalIsOpen = false" class="" role="dialog" aria-modal="true" aria-labelledby="defaultModalTitle">
<!-- Modal Dialog -->
<div x-show="modalIsOpen" x-transition:enter="transition ease-out duration-200 delay-100 motion-reduce:transition-opacity" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" class="">
<div x-show="modalIsOpen" x-transition:enter="transition ease-out duration-200 delay-100 motion-reduce:transition-opacity" x-transition:enter-start="opacity-0 scale-50" x-transition:enter-end="opacity-100 scale-100" class="">
<div x-show="modalIsOpen" x-transition:enter="transition ease-out duration-200 delay-100 motion-reduce:transition-opacity" x-transition:enter-start="opacity-0 scale-110" x-transition:enter-end="opacity-100 scale-100" class="">
<div x-show="modalIsOpen" x-transition:enter="transition ease-out duration-200 delay-100 motion-reduce:transition-opacity" x-transition:enter-start="opacity-0 translate-y-8" x-transition:enter-end="opacity-100 translate-y-0" class="">
<div x-show="modalIsOpen" x-transition:enter="transition ease-out duration-200 delay-100 motion-reduce:transition-opacity" x-transition:enter-start="opacity-0 -translate-y-8" x-transition:enter-end="opacity-100 translate-y-0" class="">
<div x-show="modalIsOpen" x-transition:enter="transition ease-out duration-200 delay-100 motion-reduce:transition-opacity" x-transition:enter-start="opacity-0 scale-y-0" x-transition:enter-end="opacity-100 scale-y-100" class="">
<!-- Dialog Header -->
<div class="">
<h3 id="defaultModalTitle" class="">Special Offer</h3>
<button @click="modalIsOpen = false" aria-label="close modal">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" stroke="currentColor" fill="none" stroke-width="1.4" class="w-5 h-5">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
<!-- Dialog Body -->
<div class="">
<p>As a token of appreciation, we have an exclusive offer just for you. Upgrade your account now to unlock premium features and enjoy a seamless experience.</p>
</div>
<!-- Dialog Footer -->
<div class="">
<button @click="modalIsOpen = false" type="button" class="">Remind me later</button>
<button @click="modalIsOpen = false" type="button" class="">Upgrade Now</button>
</div>
</div>
</div>
</div>
Modal Placement
An example of a default modal with various placement options.
Special Offer
As a token of appreciation, we have an exclusive offer just for you. Upgrade your account now to unlock premium features and enjoy a seamless experience.
<div x-data="{modalIsOpen: false}">
<button @click="modalIsOpen = true" type="button" class="">Open Modal</button>
<div x-cloak x-show="modalIsOpen" x-transition.opacity.duration.200ms x-trap.inert.noscroll="modalIsOpen" @keydown.esc.window="modalIsOpen = false" @click.self="modalIsOpen = false" class="" role="dialog" aria-modal="true" aria-labelledby="defaultModalTitle">
<!-- Modal Dialog -->
<div x-show="modalIsOpen" x-transition:enter="transition ease-out duration-200 delay-100 motion-reduce:transition-opacity" x-transition:enter-start="opacity-0 scale-50" x-transition:enter-end="opacity-100 scale-100" class="">
<!-- Dialog Header -->
<div class="">
<h3 id="defaultModalTitle" class="">Special Offer</h3>
<button @click="modalIsOpen = false" aria-label="close modal">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" stroke="currentColor" fill="none" stroke-width="1.4" class="w-5 h-5">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
<!-- Dialog Body -->
<div class="">
<p>As a token of appreciation, we have an exclusive offer just for you. Upgrade your account now to unlock premium features and enjoy a seamless experience.</p>
</div>
<!-- Dialog Footer -->
<div class="">
<button @click="modalIsOpen = false" type="button" class="">Remind me later</button>
<button @click="modalIsOpen = false" type="button" class="">Upgrade Now</button>
</div>
</div>
</div>
</div>
Modal Backdrop Style
An example of a default modal with various backdrop options.
Special Offer
As a token of appreciation, we have an exclusive offer just for you. Upgrade your account now to unlock premium features and enjoy a seamless experience.
<div x-data="{modalIsOpen: false}">
<button @click="modalIsOpen = true" type="button" class="">Open Modal</button>
<div x-cloak x-show="modalIsOpen" x-transition.opacity.duration.200ms x-trap.inert.noscroll="modalIsOpen" @keydown.esc.window="modalIsOpen = false" @click.self="modalIsOpen = false" class="" role="dialog" aria-modal="true" aria-labelledby="defaultModalTitle">
<!-- Modal Dialog -->
<div x-show="modalIsOpen" x-transition:enter="transition ease-out duration-200 delay-100 motion-reduce:transition-opacity" x-transition:enter-start="scale-0" x-transition:enter-end="scale-100" class="">
<!-- Dialog Header -->
<div class="">
<h3 id="defaultModalTitle" class="">Special Offer</h3>
<button @click="modalIsOpen = false" aria-label="close modal">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" stroke="currentColor" fill="none" stroke-width="1.4" class="w-5 h-5">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
<!-- Dialog Body -->
<div class="">
<p>As a token of appreciation, we have an exclusive offer just for you. Upgrade your account now to unlock premium features and enjoy a seamless experience.</p>
</div>
<!-- Dialog Footer -->
<div class="">
<button @click="modalIsOpen = false" type="button" class="">Remind me later</button>
<button @click="modalIsOpen = false" type="button" class="">Upgrade Now</button>
</div>
</div>
</div>
</div>
Modal Alerts
A collection of modal examples that display popup messages triggered by user actions.
Update Required
You are missing critical security updates, putting your system at risk of potential vulnerabilities.
New Update Available
A new version of the application is ready for download. Enhance your experience with the latest features and improvements.
Transaction Complete
Your funds transfer was successful. Check your balance for confirmation.
Forgot your password?
Your account will be locked after three unsuccessful login attempts.
<!-- success Modal -->
<div x-data="{ successModalIsOpen: false }">
<button @click="successModalIsOpen = true" type="button" class="">Success Modal</button>
<div x-cloak x-show="successModalIsOpen" x-transition.opacity.duration.200ms x-trap.inert.noscroll="successModalIsOpen" @keydown.esc.window="successModalIsOpen = false" @click.self="successModalIsOpen = false" class="" role="dialog" aria-modal="true" aria-labelledby="successModalTitle">
<!-- Modal Dialog -->
<div x-show="successModalIsOpen" x-transition:enter="transition ease-out duration-200 delay-100 motion-reduce:transition-opacity" x-transition:enter-start="opacity-0 scale-50" x-transition:enter-end="opacity-100 scale-100" class="">
<!-- Dialog Header -->
<div class="">
<div class="">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="" aria-hidden="true">
<path fill-rule="evenodd" d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm3.857-9.809a.75.75 0 0 0-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 1 0-1.06 1.061l2.5 2.5a.75.75 0 0 0 1.137-.089l4-5.5Z" clip-rule="evenodd" />
</svg>
</div>
<button @click="successModalIsOpen = false" aria-label="close modal">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" stroke="currentColor" fill="none" stroke-width="1.4" class="w-5 h-5">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
<!-- Dialog Body -->
<div class="">
<h3 id="successModalTitle" class="">Transaction Complete</h3>
<p>Your funds transfer was successful. Check your balance for confirmation.</p>
</div>
<!-- Dialog Footer -->
<div class="">
<button @click="successModalIsOpen = false" type="button" class="">Go to My Balance</button>
</div>
</div>
</div>
</div>
<!-- info Modal -->
<div x-data="{ infoModalIsOpen: false }">
<button @click="infoModalIsOpen = true" type="button" class="">Info Modal</button>
<div x-cloak x-show="infoModalIsOpen" x-transition.opacity.duration.200ms x-trap.inert.noscroll="infoModalIsOpen" @keydown.esc.window="infoModalIsOpen = false" @click.self="infoModalIsOpen = false" class="" role="dialog" aria-modal="true" aria-labelledby="infoModalTitle">
<!-- Modal Dialog -->
<div x-show="infoModalIsOpen" x-transition:enter="transition ease-out duration-200 delay-100 motion-reduce:transition-opacity" x-transition:enter-start="opacity-0 scale-50" x-transition:enter-end="opacity-100 scale-100" class="">
<!-- Dialog Header -->
<div class="">
<div class="">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="" aria-hidden="true">
<path fill-rule="evenodd" d="M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0Zm-7-4a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM9 9a.75.75 0 0 0 0 1.5h.253a.25.25 0 0 1 .244.304l-.459 2.066A1.75 1.75 0 0 0 10.747 15H11a.75.75 0 0 0 0-1.5h-.253a.25.25 0 0 1-.244-.304l.459-2.066A1.75 1.75 0 0 0 9.253 9H9Z" clip-rule="evenodd" />
</svg>
</div>
<button @click="infoModalIsOpen = false" aria-label="close modal">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" stroke="currentColor" fill="none" stroke-width="1.4" class="w-5 h-5">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
<!-- Dialog Body -->
<div class="">
<h3 id="infoModalTitle" class="">New Update Available</h3>
<p>A new version of the application is ready for download. Enhance your experience with the latest features and improvements.</p>
</div>
<!-- Dialog Footer -->
<div class="">
<button @click="infoModalIsOpen = false" type="button" class="">Install Updates Now</button>
</div>
</div>
</div>
</div>
<!-- warning Modal -->
<div x-data="{ warningModalIsOpen: false }">
<button @click="warningModalIsOpen = true" type="button" class="">Warning Modal</button>
<div x-cloak x-show="warningModalIsOpen" x-transition.opacity.duration.200ms x-trap.inert.noscroll="warningModalIsOpen" @keydown.esc.window="warningModalIsOpen = false" @click.self="warningModalIsOpen = false" class="" role="dialog" aria-modal="true" aria-labelledby="warningModalTitle">
<!-- Modal Dialog -->
<div x-show="warningModalIsOpen" x-transition:enter="transition ease-out duration-200 delay-100 motion-reduce:transition-opacity" x-transition:enter-start="opacity-0 scale-50" x-transition:enter-end="opacity-100 scale-100" class="">
<!-- Dialog Header -->
<div class="">
<div class="">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="" aria-hidden="true">
<path fill-rule="evenodd" d="M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0Zm-8-5a.75.75 0 0 1 .75.75v4.5a.75.75 0 0 1-1.5 0v-4.5A.75.75 0 0 1 10 5Zm0 10a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z" clip-rule="evenodd" />
</svg>
</div>
<button @click="warningModalIsOpen = false" aria-label="close modal">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" stroke="currentColor" fill="none" stroke-width="1.4" class="w-5 h-5">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
<!-- Dialog Body -->
<div class="">
<h3 id="warningModalTitle" class="">Forgot your password?</h3>
<p>Your account will be locked after three unsuccessful login attempts.</p>
</div>
<!-- Dialog Footer -->
<div class="">
<button @click="warningModalIsOpen = false" type="button" class="">Recover My Password</button>
</div>
</div>
</div>
</div>
<!-- danger Modal -->
<div x-data="{ dangerModalIsOpen: false }">
<button @click="dangerModalIsOpen = true" type="button" class="">Danger Modal</button>
<div x-cloak x-show="dangerModalIsOpen" x-transition.opacity.duration.200ms x-trap.inert.noscroll="dangerModalIsOpen" @keydown.esc.window="dangerModalIsOpen = false" @click.self="dangerModalIsOpen = false" class="" role="dialog" aria-modal="true" aria-labelledby="dangerModalTitle">
<!-- Modal Dialog -->
<div x-show="dangerModalIsOpen" x-transition:enter="transition ease-out duration-200 delay-100 motion-reduce:transition-opacity" x-transition:enter-start="opacity-0 scale-50" x-transition:enter-end="opacity-100 scale-100" class="">
<!-- Dialog Header -->
<div class="">
<div class="">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="" aria-hidden="true">
<path fill-rule="evenodd" d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16ZM8.28 7.22a.75.75 0 0 0-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 1 0 1.06 1.06L10 11.06l1.72 1.72a.75.75 0 1 0 1.06-1.06L11.06 10l1.72-1.72a.75.75 0 0 0-1.06-1.06L10 8.94 8.28 7.22Z" clip-rule="evenodd" />
</svg>
</div>
<button @click="dangerModalIsOpen = false" aria-label="close modal">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" stroke="currentColor" fill="none" stroke-width="1.4" class="w-5 h-5">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
<!-- Dialog Body -->
<div class="">
<h3 id="dangerModalTitle" class="">Update Required</h3>
<p>You are missing critical security updates, putting your system at risk of potential vulnerabilities.</p>
</div>
<!-- Dialog Footer -->
<div class="">
<button @click="dangerModalIsOpen = false" type="button" class="">Install Updates Now</button>
</div>
</div>
</div>
</div>
Video Modal
A modal that displays video content in a pop-up overlay. You can choose whether the video should automatically play when the modal opens.
<div x-data="{videoModalIsOpen: false}">
<button @click="videoModalIsOpen = true" type="button" class="">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" fill="currentColor" class="w-4 h-4">
<path fill-rule="evenodd" d="M4.5 5.653c0-1.426 1.529-2.33 2.779-1.643l11.54 6.348c1.295.712 1.295 2.573 0 3.285L7.28 19.991c-1.25.687-2.779-.217-2.779-1.643V5.653z" clip-rule="evenodd"/>
</svg>
Play Video
</button>
<div x-cloak x-show="videoModalIsOpen" x-transition.opacity.duration.200ms x-trap.inert.noscroll="videoModalIsOpen" @keydown.esc.window="videoModalIsOpen = false, $refs.video.pause()" @click.self="videoModalIsOpen = false, $refs.video.pause()" class="" role="dialog" aria-modal="true" aria-labelledby="videoModalTitle">
<!-- Modal Dialog -->
<div x-show="videoModalIsOpen" x-transition:enter="transition ease-out duration-300 delay-200" x-transition:enter-start="opacity-0 translate-y-8" x-transition:enter-end="opacity-100 translate-y-0" class="">
<!-- Close Button -->
<button type="button" x-show="videoModalIsOpen" @click="videoModalIsOpen = false, $refs.video.pause()" x-transition:enter="transition ease-out duration-200 delay-500" x-transition:enter-start="opacity-0 scale-0" x-transition:enter-end="opacity-100 scale-100" class="" aria-label="close modal">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" stroke="currentColor" fill="none" stroke-width="1.4" class="w-4 h-4">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
<!-- Video -->
<video x-ref="video" class="" controls>
<track default kind="captions" srclang="en" src="path to your .vtt file" />
<source src="https://penguinui.s3.amazonaws.com/component-assets/peng.webm" type="video/webm">
<source src="https://penguinui.s3.amazonaws.com/component-assets/peng.mp4" type="video/mp4">
Your browser does not support HTML video.
</video>
</div>
</div>
</div>
Data
List of all Alpine JS data used in this component.
Property | Description |
---|---|
modalIsOpen successModalIsOpen infoModalIsOpen warningModalIsOpen dangerModalIsOpen videoModalIsOpen |
Boolean - Modal is open/closed
|
Keyboard Navigation
Key | Action |
---|---|
Tab | Next item gets the focus |
Enter |
Modal Closed: Modal Opens Modal Open: Focused item gets selected |
Space |
Modal Closed: Modal Opens Modal Open: Focused item gets selected |
Esc | Modal Closes |