Image Card
A card component optimized for displaying images with captions.
The Image Card component is a specialized card designed for displaying images with captions. It features aspect ratio controls and optimized image display. Built from scratch using React and native HTML elements. No dependencies on any UI library.
Code
TypeScript: Copy this code into components/ui/image-card.tsx:
tsx
import * as React from "react"
import { cn } from "@/lib/utils"
interface ImageCardProps extends React.HTMLAttributes<HTMLDivElement> {
src: string
alt: string
caption?: string
aspectRatio?: "square" | "landscape" | "portrait" | "auto"
}
const ImageCard = React.forwardRef<HTMLDivElement, ImageCardProps>(
({ className, src, alt, caption, aspectRatio = "auto", ...props }, ref) => {
const getAspectRatioClass = () => {
switch (aspectRatio) {
case "square":
return "aspect-square"
case "landscape":
return "aspect-video"
case "portrait":
return "aspect-[3/4]"
case "auto":
default:
return ""
}
}
return (
<div
ref={ref}
className={cn(
"rounded-lg border-2 border-foreground bg-card text-card-foreground neobrutalism-shadow overflow-hidden",
className
)}
{...props}
>
<div className={cn("relative w-full overflow-hidden", getAspectRatioClass())}>
<img
src={src}
alt={alt}
className="h-full w-full object-cover"
/>
</div>
{caption && (
<div className="bg-primary text-primary-foreground px-4 py-2 text-center text-sm font-bold">
{caption}
</div>
)}
</div>
)
}
)
ImageCard.displayName = "ImageCard"
interface ImageCardImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {
aspectRatio?: "square" | "landscape" | "portrait" | "auto"
}
const ImageCardImage = React.forwardRef<HTMLImageElement, ImageCardImageProps>(
({ className, aspectRatio = "auto", ...props }, ref) => {
const getAspectRatioClass = () => {
switch (aspectRatio) {
case "square":
return "aspect-square"
case "landscape":
return "aspect-video"
case "portrait":
return "aspect-[3/4]"
case "auto":
default:
return ""
}
}
return (
<div className={cn("relative w-full overflow-hidden", getAspectRatioClass())}>
<img
ref={ref}
className={cn("h-full w-full object-cover", className)}
{...props}
/>
</div>
)
}
)
ImageCardImage.displayName = "ImageCardImage"
interface ImageCardCaptionProps extends React.HTMLAttributes<HTMLDivElement> {}
const ImageCardCaption = React.forwardRef<HTMLDivElement, ImageCardCaptionProps>(
({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("bg-primary text-primary-foreground px-4 py-2 text-center text-sm font-bold", className)}
{...props}
/>
)
)
ImageCardCaption.displayName = "ImageCardCaption"
export {
ImageCard,
ImageCardImage,
ImageCardCaption,
}JavaScript: Copy this code into components/ui/image-card.jsx:
jsx
import * as React from "react"
import { cn } from "@/lib/utils"
const ImageCard = React.forwardRef(
({ className, src, alt, caption, aspectRatio = "auto", ...props }, ref) => {
const getAspectRatioClass = () => {
switch (aspectRatio) {
case "square":
return "aspect-square"
case "landscape":
return "aspect-video"
case "portrait":
return "aspect-[3/4]"
case "auto":
default:
return ""
}
}
return (
<div
ref={ref}
className={cn(
"rounded-lg border-2 border-foreground bg-card text-card-foreground neobrutalism-shadow overflow-hidden",
className
)}
{...props}
>
<div className={cn("relative w-full overflow-hidden", getAspectRatioClass())}>
<img
src={src}
alt={alt}
className="h-full w-full object-cover"
/>
</div>
{caption && (
<div className="bg-primary text-primary-foreground px-4 py-2 text-center text-sm font-bold">
{caption}
</div>
)}
</div>
)
}
)
ImageCard.displayName = "ImageCard"
const ImageCardImage = React.forwardRef(
({ className, aspectRatio = "auto", ...props }, ref) => {
const getAspectRatioClass = () => {
switch (aspectRatio) {
case "square":
return "aspect-square"
case "landscape":
return "aspect-video"
case "portrait":
return "aspect-[3/4]"
case "auto":
default:
return ""
}
}
return (
<div className={cn("relative w-full overflow-hidden", getAspectRatioClass())}>
<img
ref={ref}
className={cn("h-full w-full object-cover", className)}
{...props}
/>
</div>
)
}
)
ImageCardImage.displayName = "ImageCardImage"
const ImageCardCaption = React.forwardRef(
({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("bg-primary text-primary-foreground px-4 py-2 text-center text-sm font-bold", className)}
{...props}
/>
)
)
ImageCardCaption.displayName = "ImageCardCaption"
export {
ImageCard,
ImageCardImage,
ImageCardCaption,
}Usage
TypeScript:
tsx
import { ImageCard } from "@/components/ui/image-card"
function MyComponent() {
return (
<ImageCard
src="/path/to/image.jpg"
alt="Description"
caption="Image"
/>
)
}JavaScript:
jsx
import { ImageCard } from "@/components/ui/image-card"
function MyComponent() {
return (
<ImageCard
src="/path/to/image.jpg"
alt="Description"
caption="Image"
/>
)
}Make sure you also have the lib/utils.ts file with the cn helper function.
Examples
Default
Image
With Compound Components
Beautiful Cherry Blossoms
Square Aspect Ratio
Square Image
Landscape Aspect Ratio
Landscape Image