Let’s build a fun testimonial with Astro, Tailwind CSS and Alpinejs!
Let’s use Astro to make a template so we don’t have to write the same code over and over. We’ll put our data in an array and send it to the Alpine.js component.
This array represents a single testimonial object within a larger collection of testimonials. Each object in the collection includes several key pieces of information about the testimonial:
id
: Unique identifier for each testimonial.content
: The testimonial text.imageUrl
: Link or path to an associated image.name
: The name of the testimonial provider.title
: Their professional title or role.Here’s the code snippet for the testimonial object:
{
id: 1,
content:
"Johnny is like a unicorn in a field of horses, magically bridging the gap between design and coding...",
imageUrl:
"https://images.unsplash.com/photo-1543610892-0b1f7e6d8ac1?w=800&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MjN8fGF2YXRhcnxlbnwwfHwwfHx8MA%3D%3D",
name: "Jhonny Mnemonic",
title: "Chief Wizard of Nowhere Land",
},
Alpine.js facilitates the interactive elements within the testimonials section through:
x-data
initializes a component state, testimonialActive
, which tracks the currently active testimonial. This state is crucial for determining which testimonial content to display.In this cse we are using the 1 testimonial
<div x-data="{ testimonialActive: 1 }">
Adjust the number in testimonialActive to set a different default testimonial.
2.3. Conditional Rendering: x-show directive dynamically shows or hides a testimonial based on whether its index matches the testimonialActive state.
<div x-show={`testimonialActive === ${index + 1}`}>
Complete component for rendering testimonials dynamically:
<!-- Dynamically render testimonials -->
{
testimonials.map((testimonial, index) => (
<div
class="pb-6 text-neutral-200 font-medium mx-auto lg:h-64 italic serif text-balance items-center text-center text-4xl "
x-show={`testimonialActive === ${index + 1}`}
style="display: none;">
<p>
<span class="text-[#a180ea]">"</span>
{testimonial.content}
<span class="text-[#a180ea]">"</span>
</p>
</div>
))
}
<!-- Dynamically render name and role -->
{
testimonials.map((testimonial, index) => (
<div
class="text-center py-6"
x-show={`testimonialActive === ${index + 1}`}
style="display: none;">
<h2 class="text-white font-medium text-base">{testimonial.name}</h2>
<a
href="#"
class="text-xs text-neutral-400">
{testimonial.title}
</a>
</div>
))
}
@click.prevent
to change the active testimonial based on the user’s selection..<button @click.prevent={`testimonialActive = ${index + 1}`}>
For navigating between testimonials:
<!--
Buttons to change the active testimonial
Dynamically render avatars
-->
{
testimonials.map((testimonial, index) => (
<button
@click.prevent={`testimonialActive = ${index + 1}`}
class="inline-block mx-2 font-bold text-center rounded-xl focus:outline-none focus:ring-2 ring-offset-2 ring-white ring-offset-[#141521] size-12">
<img
class="inline-block size-12 rounded-xl object-cover"
src={testimonial.imageUrl}
alt="#_"
/>
</button>
))
}
That was it, short, brief and straight to the point, don’t forget to grab the code and do something cool with it!
/Michael Andreuzza
Get lifetime access to every theme available today for $199 $139 and own
them forever. Plus, new themes, lifetime updates, use on unlimited
projects and enjoy lifetime support.
— No subscription required!