Text tiles that reveal a full photo on hover or focus, with the text dropping and turning white over a gradient. React and Tailwind CSS.
FacilitiesHoverRevealGrid.tsx
// Facilities grid: plain text tiles that reveal a photo on hover, with the
// text dropping and turning white over a dark gradient.
// Pure Tailwind, no dependencies. Works with Tailwind v3 and v4.
type Facility = { title: string; description: string; image: string };
type Props = {
heading?: string;
facilities?: Facility[];
};
const img = (id: string) => `https://images.unsplash.com/photo-${id}?w=1000&q=80&auto=format&fit=crop`;
const DEFAULT_FACILITIES: Facility[] = [
{ title: "Spa & wellness", description: "Treatment rooms, a hammam and a quiet relaxation pool.", image: img("1600334129128-685c5582fd35") },
{ title: "Pool gardens", description: "Two pools set in palms, with cabanas and a pool bar.", image: img("1520250497591-112f2f40a3f4") },
{ title: "Fine dining", description: "Seasonal tasting menus from our chef, every evening.", image: img("1414235077428-338989a2e8c0") },
{ title: "Private dining", description: "A table for twelve for celebrations and long lunches.", image: img("1600812703042-38e573598898") },
{ title: "The lounge", description: "Coffee by day, cocktails and live piano by night.", image: img("1697124510322-27ef594f67fd") },
{ title: "Terrace bar", description: "Sunset drinks and small plates over the water.", image: img("1559339352-11d035aa65de") },
];
export default function FacilitiesRevealGrid({ heading = "Facilities", facilities = DEFAULT_FACILITIES }: Props) {
return (
<section className="bg-white px-5 py-20 font-['Inter',ui-sans-serif,system-ui,sans-serif] antialiased md:px-10 md:py-28">
<div className="mx-auto max-w-7xl">
<h2 className="mb-12 text-center font-['Playfair_Display',Georgia,serif] text-[clamp(2.25rem,4.5vw,3.75rem)] leading-tight text-[#49031E]">{heading}</h2>
<div className="grid grid-cols-1 gap-2 md:grid-cols-3">
{facilities.map((item) => (
<div key={item.title} tabIndex={0} className="group relative flex min-h-[420px] items-center justify-center overflow-hidden bg-[#F4E9EE] p-8 outline-none">
<img src={item.image} alt="" loading="lazy" className="absolute inset-0 h-full w-full scale-110 object-cover opacity-0 transition-all duration-700 group-hover:scale-100 group-hover:opacity-100 group-focus:scale-100 group-focus:opacity-100" />
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/20 to-transparent opacity-0 transition-opacity duration-700 group-hover:opacity-100 group-focus:opacity-100" />
<div className="relative z-10 max-w-sm text-center transition-all duration-500 group-hover:translate-y-28 group-focus:translate-y-28">
<h3 className="font-['Playfair_Display',Georgia,serif] text-3xl capitalize text-[#49031E] transition-colors duration-500 group-hover:text-white group-focus:text-white">{item.title}</h3>
<p className="mt-3 text-neutral-600 transition-colors duration-500 group-hover:text-neutral-200 group-focus:text-neutral-200">{item.description}</p>
</div>
</div>
))}
</div>
</div>
</section>
);
}
How to use it
- Make sure your Next.js or React project has Tailwind CSS set up (v3 or v4 both work).
- Create
components/FacilitiesHoverRevealGrid.tsxand paste the code. - Import it into a page and replace the sample text and images with your own.
