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

Content

PreviousNext

The composition layer the route's page.tsx delegates to.

content.tsx owns data fetching (server) or hook orchestration (client) and composes children. Pages stay thin (auth + tenant + render); real logic lives here.

Two flavours

FlavourWhen
Server contentAsync function, fetches via queries.ts, no "use client"
Client content"use client", hooks/state, fetches via server actions

Decision tree:

NeedsUse
Hooks, events, browser APIsClient content
Data fetching + compositionServer content
BothServer content rendering client sub-components

Rules

#Rule
1export default [async] function XxxContent()
2import type for type-only imports
3Stay under ~150 lines — split sub-components beyond that
4Typed dictionary slice (Dictionary["school"]["grades"]), never any
5All UI text from the dictionary — no hardcoded strings, no isArabic ? ternaries
6Use lang: Locale, not locale
7Server content: extract queries to queries.ts
8Client content: fetch via server actions from actions.ts

Server listing — canonical shape

import type { Locale } from "@/components/internationalization/dictionaries"
import type { Dictionary } from "@/components/internationalization/types"
 
import { getStudentList } from "./queries"
import { StudentsTable } from "./table"
 
interface Props {
  searchParams: Promise<Record<string, string | string[] | undefined>>
  dictionary: Dictionary["school"]["students"]
  lang: Locale
}
 
export default async function StudentsContent({
  searchParams,
  dictionary,
  lang,
}: Props) {
  const params = await searchParams
  const students = await getStudentList(params)
  return <StudentsTable data={students} dictionary={dictionary} lang={lang} />
}

Templates

TemplateReference
Server listingschool-dashboard/listings/students/content.tsx
Server dashboardschool-dashboard/dashboard/content.tsx
Client interactiveschool-dashboard/attendance/manual/content.tsx
Server compositionschool-dashboard/profile/content.tsx
Client wizard stepschool-marketing/application/personal/content.tsx

Anti-patterns

  • Monolith content — files over 300 lines should split into sub-components.
  • dictionary: any — type the slice.
  • Dictionary accepted but ignored.
  • Inline Prisma queries — belong in queries.ts.
  • Inline isArabic ternaries — use the dictionary slice.
  • db imports in page.tsx — pages stay thin.
  • Wrong "use client" — only present when client logic is needed.
  • Inline SVGs — extract to a separate file or icon registry.
  • Duplicate type definitions — share via types.ts.
  • Sequential await for permission checks — parallelise with Promise.all.
  • console.log left in.

Naming

  • File: content.tsx.
  • Function: <Feature>Content PascalCase, default export.

Client boundary

When content.tsx needs interactivity (modals, view toggles, form state), keep content.tsx a pure server component and delegate to a sibling client.tsx that owns the "use client" directive. The server content.tsx fetches data and forwards it to <XxxClient />; the client component composes interactive leaves (form.tsx, table.tsx, detail.tsx). Use this split only when actually needed — a listing that just renders a server-fetched table doesn't need a client boundary.

"use client"
 
import { useState } from "react"
 
import { Button } from "@/components/ui/button"
import type { Dictionary } from "@/components/internationalization/types"
 
import { TeacherForm } from "./form"
import { TeachersTable } from "./table"
import type { TeacherListItem } from "./types"
 
interface Props {
  data: TeacherListItem[]
  dictionary: Dictionary["school"]["teachers"]
  lang: Locale
}
 
export function TeachersClient({ data, dictionary, lang }: Props) {
  const [showForm, setShowForm] = useState(false)
  return (
    <>
      <Button onClick={() => setShowForm(true)}>{dictionary.add}</Button>
      <TeachersTable data={data} dictionary={dictionary} lang={lang} />
      {showForm && (
        <TeacherForm
          dictionary={dictionary}
          onClose={() => setShowForm(false)}
        />
      )}
    </>
  )
}

The matching server content.tsx stays trivial — fetch, then forward.

Boundary roles

FileRole
page.tsxAuth + tenant + render <XxxContent />
content.tsxServer, fetches data, renders <XxxClient />
client.tsxClient, manages state, composes leaves
form.tsxClient leaf — RHF + Zod, calls server action
table.tsxClient leaf — DataTable wrapper
actions.tsServer actions called from leaves
queries.tsServer reads called from content.tsx

See also

  • Pattern
  • Page
  • Queries
  • Actions
LayoutTypes

On This Page

Two flavoursRulesServer listing — canonical shapeTemplatesAnti-patternsNamingClient boundaryBoundary rolesSee also

Built by Databayt ·

Welcome to balqalam.

A great journey is about to begin.