Resource Detail
The resource detail pattern is used for pages that display a single item in depth — an event page, a news article, a weather location, or a user profile. It complements the Resource Index pattern.
Anatomy
A resource detail page consists of:
- Breadcrumb — navigation context (e.g., Events > Music > Harare Jazz Festival)
- Header — title, metadata, primary action
- Content body — the main content area
- Sidebar — related information, actions, metadata (optional, desktop only)
- Related items — suggestions at the bottom
Layout
Use the DetailLayout component for consistent detail pages:
<DetailLayout>
{/* Breadcrumb */}
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/events">Events</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Harare Jazz Festival</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
{/* Header */}
<div className="mt-6">
<Badge variant="outline">Music</Badge>
<h1 className="mt-2 font-serif text-3xl font-bold">Harare Jazz Festival</h1>
<p className="mt-2 text-muted-foreground">
Annual jazz celebration featuring artists from across Southern Africa.
</p>
</div>
{/* Two-column layout */}
<div className="mt-8 grid gap-8 lg:grid-cols-[1fr_300px]">
<main>{/* Content body */}</main>
<aside className="hidden lg:block">{/* Sidebar */}</aside>
</div>
</DetailLayout>Header patterns
With status and actions
<div className="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
<div>
<div className="flex items-center gap-2">
<h1 className="font-serif text-3xl font-bold">Event Title</h1>
<StatusIndicator status="active" />
</div>
<p className="mt-1 text-muted-foreground">Created 3 days ago</p>
</div>
<div className="flex gap-2">
<Button variant="outline">Edit</Button>
<ShareDialog />
</div>
</div>With image
<div className="overflow-hidden rounded-xl">
<AspectRatio ratio={16 / 9}>
<img src={imageUrl} alt={title} className="size-full object-cover" />
</AspectRatio>
</div>
<h1 className="mt-6 font-serif text-3xl font-bold">{title}</h1>Sidebar content
The sidebar typically contains:
<aside className="space-y-6">
{/* Key details card */}
<Card>
<CardHeader>
<CardTitle className="text-base">Details</CardTitle>
</CardHeader>
<CardContent className="space-y-3">
<div className="flex items-center gap-2 text-sm">
<Calendar className="size-4 text-muted-foreground" />
<span>15 June 2026</span>
</div>
<div className="flex items-center gap-2 text-sm">
<MapPin className="size-4 text-muted-foreground" />
<span>Harare, Zimbabwe</span>
</div>
</CardContent>
</Card>
{/* Actions */}
<Card>
<CardContent className="pt-6">
<Button className="w-full">Register</Button>
</CardContent>
</Card>
</aside>Mobile considerations
On mobile, the sidebar content moves below the main content:
<div className="grid gap-8 lg:grid-cols-[1fr_300px]">
<main>{/* Content — always first */}</main>
<aside>{/* Sidebar — below on mobile, right on desktop */}</aside>
</div>For critical sidebar content (like a “Register” button), consider duplicating it as a sticky bottom bar on mobile:
<div className="fixed inset-x-0 bottom-0 border-t border-border bg-background p-4 lg:hidden">
<Button className="w-full">Register</Button>
</div>Related items
At the bottom of the detail page, show related items using the card grid pattern:
<section className="mt-12">
<h2 className="text-xl font-semibold">Related events</h2>
<div className="mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
{relatedItems.map((item) => (
<Card key={item.id}>
<CardHeader>
<CardTitle className="text-base">{item.title}</CardTitle>
</CardHeader>
<CardContent>
<p className="text-sm text-muted-foreground">{item.description}</p>
</CardContent>
</Card>
))}
</div>
</section>Back navigation
Always provide a way to return to the index page:
<Button variant="ghost" size="sm" asChild>
<a href="/events" className="gap-2">
<ArrowLeft className="size-4" />
Back to events
</a>
</Button>Last updated on