Back to ShowcaseFull Canvas Preview
CardsFeatured2 files

Gradient Pattern Card

A sleek dark-mode card component featuring a custom dotted mesh pattern background, gradient light fade overlay, crisp media preview container, and action CTA buttons. Displays 3 responsive cards with custom media.

ReactTailwind CSSCardGradientPatternDark ModeUI

Live Component Preview

Cosmic orange flower with a glowing galaxy at its center

Cosmic Bloom

A surreal orange flower blooming against a deep cosmic backdrop and calm, with a luminous galaxy spiraling through its center.

Pink cherry blossom tree in a soft blue atmospheric landscape

Cherry Blossom Dream

Delicate pink cherry blossoms emerging from a soft winter-blue atmosphere, creating a calm and ethereal painted landscape.

Abstract green and teal landscape with flying white birds

Emerald Flight

A vibrant green and teal abstract landscape filled with soft organic textures and a flock of birds drifting through the scene.

components/blocks/cards/cards.tsx
cards.tsx
import React from "react";
import DotedPattern from "./doted-pattern";
export interface CardItemProps {
id?: string | number;
title?: string;
description?: string;
image?: string;
imageAlt?: string;
tag?: string;
previewLabel?: string;
docsLabel?: string;
onPreview?: () => void;
onDocs?: () => void;
onActionClick?: () => void;
className?: string;
}
export interface CardsProps {
cards?: CardItemProps[];
className?: string;
// Fallback single card props for backward compatibility
title?: string;
description?: string;
image?: string;
imageAlt?: string;
tag?: string;
previewLabel?: string;
docsLabel?: string;
onPreview?: () => void;
onDocs?: () => void;
onActionClick?: () => void;
}
export const DEFAULT_CARDS: CardItemProps[] = [
{
id: "card-1",
title: "Cosmic Bloom",
description:
"A surreal orange flower blooming against a deep cosmic backdrop and calm, with a luminous galaxy spiraling through its center.",
image:
"https://pbs.twimg.com/media/HP0V9iwaQAAsa56?format=jpg&name=large",
imageAlt: "Cosmic orange flower with a glowing galaxy at its center",
tag: "Surreal Art",
previewLabel: "Preview",
docsLabel: "Docs",
},
{
id: "card-2",
title: "Cherry Blossom Dream",
description:
"Delicate pink cherry blossoms emerging from a soft winter-blue atmosphere, creating a calm and ethereal painted landscape.",
image:
"https://pbs.twimg.com/media/HPtKeIlbQAA96T8?format=jpg&name=4096x4096",
imageAlt: "Pink cherry blossom tree in a soft blue atmospheric landscape",
tag: "Digital Painting",
previewLabel: "Preview",
docsLabel: "Docs",
},
{
id: "card-3",
title: "Emerald Flight",
description:
"A vibrant green and teal abstract landscape filled with soft organic textures and a flock of birds drifting through the scene.",
image:
"https://pbs.twimg.com/media/HPxBy4OXAAEG4Km?format=jpg&name=4096x4096",
imageAlt: "Abstract green and teal landscape with flying white birds",
tag: "Abstract Art",
previewLabel: "Preview",
docsLabel: "Docs",
},
];
export const CardItem: React.FC<CardItemProps> = ({
title = "Gradient Effect",
description = "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facilis alias quaerat sint.",
image = "/previews/card1.png",
imageAlt = "Card preview",
tag,
previewLabel = "Preview",
docsLabel = "Docs",
onPreview,
onDocs,
onActionClick,
className = "",
}) => {
const repeatCount = 11;
return (
<div className={`w-full max-w-95 rounded-4xl h-fit border border-neutral-700/60 bg-neutral-800 p-px shadow-xl hover:shadow-2xl transition-all duration-300 ${className}`}>
<div className="relative w-full rounded-4xl border border-neutral-600 bg-neutral-800 overflow-hidden flex flex-col">
{/* Background Dot Pattern at bottom */}
<div className="absolute inset-x-0 bottom-0 h-1/2 flex overflow-hidden pointer-events-none z-0">
{Array.from({ length: repeatCount }, (_, index) => (
<div key={index} className="shrink-0">
<DotedPattern />
</div>
))}
</div>
{/* Gradient Mask Over Background Pattern */}
<div className="absolute inset-x-0 bottom-0 h-1/2 bg-linear-to-b from-neutral-800 from-40% to-neutral-800/10 pointer-events-none z-1 rounded-b-[30px]" />
{/* Card Content starting right at top */}
<div className="relative z-10 flex flex-col justify-start w-full p-1.5 gap-2.5">
{/* Image Section at top */}
<div className="relative w-full rounded-4xl border border-neutral-600/80 p-px overflow-hidden bg-neutral-900/50">
<div className="w-full h-60 overflow-hidden rounded-[28px] relative group p-px">
<img
className="w-full h-full object-cover flex self-center transition-transform duration-500 ease-out rounded-4xl"
src={image}
alt={imageAlt || title}
/>
</div>
</div>
{/* Text Content & Buttons */}
<div className="w-full flex flex-col gap-2 px-3 pb-2">
<div className="w-full flex items-center justify-between gap-2 ">
<h3 className="text-sm font-semibold text-neutral-100 truncate tracking-tight">{title}</h3>
<div className="flex items-center justify-center p-1 rounded-full hover:bg-neutral-700/50 transition-colors shrink-0">
<button
type="button"
aria-label={`Open ${title}`}
onClick={onActionClick}
className="cursor-pointer flex items-center justify-center text-blue-500 hover:text-blue-400 transition-colors"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
>
<path
d="M21.25 12C21.25 17.1086 17.1086 21.25 12 21.25C6.89137 21.25 2.75 17.1086 2.75 12C2.75 6.89137 6.89137 2.75 12 2.75C12.4142 2.75 12.75 2.41421 12.75 2C12.75 1.58579 12.4142 1.25 12 1.25C6.06294 1.25 1.25 6.06294 1.25 12C1.25 17.9371 6.06294 22.75 12 22.75C17.9371 22.75 22.75 17.9371 22.75 12C22.75 11.5858 22.4142 11.25 22 11.25C21.5858 11.25 21.25 11.5858 21.25 12Z"
fill="#3B82F6"
stroke="#3B82F6"
strokeWidth="0.5"
/>
<path
d="M12.4697 10.4697C12.1768 10.7626 12.1768 11.2374 12.4697 11.5303C12.7626 11.8232 13.2374 11.8232 13.5303 11.5303L21.25 3.81066V7.34375C21.25 7.75796 21.5858 8.09375 22 8.09375C22.4142 8.09375 22.75 7.75796 22.75 7.34375V2C22.75 1.58579 22.4142 1.25 22 1.25H16.6562C16.242 1.25 15.9062 1.58579 15.9062 2C15.9062 2.41421 16.242 2.75 16.6562 2.75H20.1893L12.4697 10.4697Z"
fill="#3B82F6"
stroke="#3B82F6"
strokeWidth="0.5"
/>
</svg>
</button>
</div>
</div>
<div className="w-full">
<p className="text-[12px] text-neutral-400 leading-relaxed line-clamp-3">
{description}
</p>
</div>
<div className="w-full pt-1.5 flex items-center gap-2">
<button
type="button"
onClick={onPreview}
className="text-[13px] font-medium bg-neutral-100 text-neutral-900 hover:bg-white rounded-full px-4 py-1.5 transition-all duration-200 cursor-pointer active:scale-95 shadow-sm"
>
{previewLabel}
</button>
<button
type="button"
onClick={onDocs}
className="text-[13px] font-medium text-neutral-300 rounded-full border border-neutral-600 hover:border-neutral-500 hover:bg-neutral-700/50 px-4 py-1.5 transition-all duration-200 cursor-pointer active:scale-95"
>
{docsLabel}
</button>
</div>
</div>
</div>
</div>
</div>
);
};
const Cards: React.FC<CardsProps> = ({
cards,
className = "",
title,
description,
image,
imageAlt,
tag,
previewLabel,
docsLabel,
onPreview,
onDocs,
onActionClick,
}) => {
// If specific single-card props are explicitly provided without a cards array
if (!cards && (title || image || description)) {
return (
<div className={`w-full flex items-center justify-center p-4 ${className}`}>
<CardItem
title={title}
description={description}
image={image}
imageAlt={imageAlt}
tag={tag}
previewLabel={previewLabel}
docsLabel={docsLabel}
onPreview={onPreview}
onDocs={onDocs}
onActionClick={onActionClick}
/>
</div>
);
}
const items = cards || DEFAULT_CARDS;
return (
<div className={`w-full flex flex-wrap items-center justify-center gap-6 p-4 sm:p-6 ${className}`}>
{items.map((item, index) => (
<CardItem
key={item.id || index}
title={item.title}
description={item.description}
image={item.image}
imageAlt={item.imageAlt}
tag={item.tag}
previewLabel={item.previewLabel}
docsLabel={item.docsLabel}
onPreview={item.onPreview}
onDocs={item.onDocs}
onActionClick={item.onActionClick}
/>
))}
</div>
);
};
export default Cards;