0%
balqalam Logo
balqalam
FeaturesCommunityPricingDocumentation
Login
  • Introduction
  • Pitch
  • Hogwarts
  • Live Demo
  • MVP
  • Roadmap
  • Launch Sprint
  • PRD
  • Get Started
  • Localhost
  • Architecture
  • Structure
  • Pattern
  • Page
  • Layout
  • Content
  • Types
  • Config
  • Actions
  • Queries
  • Authorization
  • Validation
  • Form
  • Table
  • Detail
  • Card
  • Util
  • Hooks
  • List Params
  • Views
  • README.md
  • ISSUE.md
  • Technology Stack
  • Database
  • File
  • CDN Assets
  • Entry Points
  • Dashboard
  • Authentication
  • Credentials
  • OAuth
  • Flow Diagrams
  • Multi-Tenancy
  • Offline
  • Onboarding
  • Onboarding Videos
  • Add Values
  • Admission
  • Application
  • Attendance
  • Compliance
  • Profile
  • Exams
  • Exam Wizard
  • Timetable
  • Classrooms
  • Notifications
  • Conference
  • LMS (Lumos)
Finance
  • Finance
  • Fee Management
  • Invoice
  • Wallet
  • Salary
  • Payroll
  • Timesheet
  • Expenses
  • Budget
  • Receipt
  • Accounts
  • Banking
  • Reports
  • Dashboard
  • Permissions
  • Messages
  • Integration Flow
  • Provision
  • AI Document Processing
  • Document Intelligence
  • Internationalization
  • Translation
  • Translation Guide
  • Icons
  • Docs Factory
  • Inspiration
  • Listings
  • Teachers
  • Students
  • Catalog
  • Library
  • Contributing
  • Code of conduct
  • GitHub Workflow
  • Database Seeds
  • Database Safety
  • Test Accounts
  • Playwright
  • Prettier
  • Block Rebound
Sales & GTM
  • Marketing Brief
  • Sales
  • Go-to-market
  • Marketing
  • Admission — Feature Spotlight
  • Pilot Program
  • Leads
  • Proposal
  • Outreach Templates
  • Case Study
  • Competitors
  • Landing-page teardown
  • Competitor FAQ
  • Business model
  • Shared economy
  • Traction
Fundraising & Ecosystem
  • Get Support
  • Investor Deck
  • Data Room
  • Investors
  • Accelerators
  • Incubators
  • Grants
  • Sponsors
  • Partners
  • Competitions & Hackathons
  • Universities & Training Centers

Detail

PreviousNext

Single-entity detail view — error state, header, info cards, optional tabs.

detail.tsx renders a single-entity detail view. Data flows in via props from content.tsx — the detail never fetches itself. Standard layout: error state → header with back button → info card grid → tabs for sub-sections → loading skeleton.

Categories

CategoryShapeReference
School-dashboard full-pageFull-page detail with tabslistings/announcements/detail.tsx
SaaS-dashboard sheet/sidebarCompact admin overview with quick actionssaas-dashboard/tenants/detail.tsx
Server componentNo "use client", pure displayexams/results/detail.tsx

Rules

#Rule
1Standard props: { data, error, dictionary, lang }
2Handle error state first with <Alert variant="destructive">
3Export a Loading skeleton matching the layout
4Use <Tabs> for 3+ distinct information groups
5Stay under ~300 lines — extract tab content to separate files

Canonical example

"use client"
 
import Link from "next/link"
import { ArrowLeft, CircleAlert } from "lucide-react"
 
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Skeleton } from "@/components/ui/skeleton"
 
interface Props {
  data: AnnouncementDetailResult | null
  error?: string | null
  dictionary: Dictionary
  lang: Locale
}
 
export function AnnouncementDetail({ data, error, dictionary, lang }: Props) {
  const t = dictionary?.school?.announcements
 
  // 1. Error state first
  if (error || !data) {
    return (
      <div className="space-y-4">
        <Button variant="ghost" asChild>
          <Link href={`/${lang}/announcements`}>
            <ArrowLeft className="me-2 h-4 w-4" />
            {t.back}
          </Link>
        </Button>
        <Alert variant="destructive">
          <CircleAlert className="h-4 w-4" />
          <AlertTitle>{t.errorTitle}</AlertTitle>
          <AlertDescription>{error || t.notFound}</AlertDescription>
        </Alert>
      </div>
    )
  }
 
  // 2. Header + info grid + body
  return (
    <div className="space-y-6">
      <div className="flex items-center gap-4">
        <Button variant="ghost" asChild>
          <Link href={`/${lang}/announcements`}>
            <ArrowLeft className="me-2 h-4 w-4" />
          </Link>
        </Button>
        <div>
          <h2>{data.title}</h2>
          <Badge variant={data.published ? "default" : "secondary"}>
            {data.published ? t.published : t.draft}
          </Badge>
        </div>
      </div>
      <Card>
        <CardHeader><CardTitle>{t.title}</CardTitle></CardHeader>
        <CardContent><div className="prose max-w-none">{data.body}</div></CardContent>
      </Card>
    </div>
  )
}
 
// 3. Loading skeleton matching layout
export function Loading() {
  return (
    <div className="space-y-6">
      <Skeleton className="h-8 w-48" />
      <div className="grid gap-4 md:grid-cols-3">
        <Skeleton className="h-32" />
        <Skeleton className="h-32" />
        <Skeleton className="h-32" />
      </div>
      <Skeleton className="h-64" />
    </div>
  )
}

Server vs client

NeedSolution
Back navigation<Link> (server) preferred over router.back() (client)
Action buttonsCallbacks from client.tsx
Tab stateURL-based tabs (server) or useState (client)
Interactive content (video, form)Extract to client sub-component

Prefer server component detail. Add "use client" only when interactivity is required.

Standard layout

1. Error state → Alert with back button
2. Header → Back button + title + status badge
3. Info cards → Grid of key metrics
4. Tabs → Sub-sections (overview, history, etc.)
5. Loading → Skeleton matching layout

Anti-patterns

  • Monolithic detail.tsx files (e.g. catalog/detail.tsx) — split tabs into separate files.
  • Missing Loading skeleton — consumers shouldn't make up ad-hoc skeletons.
  • Data fetching inside detail — receive via props from content.tsx.
  • Client component just for router.back() — use <Link> instead.

What belongs where

ContentInNot in
Detail view renderingdetail.tsxcontent.tsx
Data fetchingcontent.tsxdetail.tsx
Loading skeletondetail.tsxpage.tsx
Tab content (>100 lines)Separate file (detail-overview.tsx)detail.tsx
Detail result typetypes.tsdetail.tsx
Error Alertdetail.tsxcontent.tsx

See also

  • Pattern
  • Content
  • Card
  • Types
TableCard

On This Page

CategoriesRulesCanonical exampleServer vs clientStandard layoutAnti-patternsWhat belongs whereSee also

Built by Databayt ·

Welcome to balqalam.

A great journey is about to begin.