Skip to main content
Reference

Coding Conventions

TypeScript, React, and file naming conventions. No any, no console.log, Zod at edges.

Coding Conventions

Purpose: Framework coding standards for new projects. Copy relevant sections into your project's CLAUDE.md and customize.

Core principles

1. Template-first rule

Before designing or building any UI, ask: "Why can't I use the templates we already bought?"

  • Check Shadcnblocks Premium first — Only build custom if no suitable template exists or modification would exceed building fresh
  • Gap documentation — See standards/reference/premium-blocks.md for the full catalog and gap documentation process

2. Toasts via shadcn Sonner wrapper

  • Always import Toaster — From @/components/ui/sonner, never directly from "sonner"
  • No richColors — It bypasses theme variables
import { Toaster } from "@/components/ui/sonner"
<Toaster position="bottom-right" />

3. localStorage key registry

Maintain a registry of all localStorage keys in the project's CLAUDE.md to prevent collisions across features. Each entry documents the key, its purpose, and the feature that owns it.

## localStorage Keys

| Key | Purpose | Owner |
|-----|---------|-------|
| `theme` | Selected color theme | Theme system |
| `font-family` | Selected font | Appearance |
| `sidebar:state` | Sidebar open/collapsed | Admin scaffold |
  • Add new keys to the registry — When introducing localStorage usage
  • Check the registry first — Before choosing a key name

4. Server state vs client state

  • TanStack Query — Data from server (API calls, cached data)
  • Zustand — UI state (sidebar open, theme, local preferences)

Never put server data in Zustand. Never fetch with Zustand.

5. Prototype exception

  • date-fns in scaffold — Required by shadcn/ui Calendar; acceptable because prototypes are never promoted to production
  • Production code — Must use Luxon per Locked Decisions
    • Native Date is also prohibited in production

Code patterns

Parameterize, don't duplicate

When building responsive variants (mobile vs desktop), use a prop to control behavior -- don't create two near-identical components.

function LockMultiSelect({ compact = false }: { compact?: boolean }) {
  // Single component, behavior branches on `compact`
}

Smart column hiding

When data quality varies by filter context, auto-hide columns with poor coverage rather than showing mostly-empty cells.

const actorCoverage = events.filter(e => e.actor).length / events.length;
const showActorColumn = actorCoverage >= 0.5; // 50% threshold

Scaffold extension pattern

When building features on the prototype scaffold, follow this directory structure to keep feature code separate from scaffold infrastructure:

Directory Purpose Reset behavior
components/ui/ shadcn/ui primitives (scaffold) Preserved
components/admin/ Admin scaffold components (sidebar, header, data table) Preserved
components/app/ Feature components built for this project Cleared on reset
lib/data/ Zod schemas + seed data (scaffold) Preserved
lib/ (other files) Feature business logic, stores, utilities Cleared on reset
app/(admin)/ Admin routes and layouts (scaffold) Preserved
app/ (other routes) Feature pages Cleared on reset

Extension rules

  1. Never modify scaffold files — Don't edit components/admin/, components/ui/, lib/data/, or app/(admin)/layout.tsx for feature work
  2. Place feature components in components/app/ — Reusable components built during feature development
  3. Place feature logic in lib/ — Stores, utilities, and helpers outside of lib/data/
  4. Extend the admin layout via composition — Add feature-specific headers or navigation by rendering them inside the admin layout's children slot, not by modifying the layout itself
  5. Register shell components — If you define a layout component (e.g., AppHeader), verify it's actually rendered in the appropriate layout

Last updated: March 2026

Search Framework Explorer

Search agents, skills, and standards