Demo
Code
{# Pre-rendered like everything else #}
{% if sprig.isInclude %}
<div class="component-wrapper" x-data="modal()">
<button
sprig
s-target="#dynamic-modal-content"
s-indicator="#dynamic-modal-content"
x-on:click="open"
class="px-4 py-1 text-night text-lg bg-sand vw-600 rounded-full"
>
Open the Modal
</button>
<div x-cloak x-show="isOpen()" class="modal">
<div class="modal-content" x-on:click.away="close">
<div class="modal-header bg-gray-100">
<h3 class="vw-500">Sample Modal with Dynamic Content</h3>
<button class="p-3 bg-gray-300 text-gray-800 rounded" x-on:click="close">
{{ svg('@svg/x.svg')|attr({class: 'w-5 h-5 stroke-2'}) }}
</button>
</div>
<div id="dynamic-modal-content" class="modal-body">
{% for i in 0..4 %}
{% set options = {
size: loop.first ? 'md' : 'lg',
classList: loop.first ? 'my-4' : 'my-2'
} %}
{{ include('_atoms/text-loader', options, with_context=false) }}
{% endfor %}
</div>
<div class="modal-footer">
<button type="button" x-on:click="close" class="vw-500">Close</button>
</div>
</div>
</div>
</div>
<script>
function modal(){
return {
show: false,
open(){
this.show = true;
},
close(){
this.show = false;
},
isOpen(){
return this.show === true;
}
}
}
</script>
{% endif %}
{# Dynamically Loaded when Sprig is triggered #}
{% if sprig.isRequest %}
{# Call any Craft queries here #}
{% set posts = craft.entries().section('blogPosts').limit(4).all() %}
<h4 class="my-4">Fetched Blog Post Titles</h4>
{% for post in posts %}
<p class="my-2">{{ post.title }}</p>
{% endfor %}
{% endif %}
{# Be sure that HTMX is loaded before calling the Sprig component#}
{{ sprig.script }}
{# call the Sprig component #}
{{ sprig('_sprig/modal.twig') }}
Bonus - Skeleton Loader Include
{# @var size #}
{# @var classList #}
{% set size = size ?? null %}
{% set classList = classList ?? '' %}
{% switch size %}
{% case 'xs' %}
{% set sizeClass = 'w-1/6' %}
{% case 'sm' %}
{% set sizeClass = 'w-1/4' %}
{% case 'md' %}
{% set sizeClass = 'w-1/2' %}
{% case 'lg' %}
{% set sizeClass = 'w-2/3' %}
{% case 'xl' %}
{% set sizeClass = 'w-full' %}
{% case 'full' %}
{% set sizeClass = 'w-full' %}
{% default %}
{% set sizeClass = 'w-full' %}
{% endswitch %}
<span class="animate-pulse h-4 bg-gray-400 rounded loader {{ sizeClass }} {{ classList }}"></span>
Here I'm using Tailwind, but I've pasted the raw CSS below. Feel free to adjust the width variable as needed.
.loader{
display: none;
}
.htmx-request .loader{
display: block;
}
.skeleton-loader{
background-color: rgba(156, 163, 175, 1);
border-radius: 0.25rem;
height: 1rem;
width: 50%;
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
margin-top: .5rem;
margin-bottom: .5rem;
}
@keyframes pulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: .5;
}
}