Contact Us

Development Guidelines

DOC-00042 guide implementor, developer

Overview

This document covers the coding conventions and development standards for the project. It consolidates rules from AGENTS.md and the project charter into a single reference for human developers. For component-specific authoring patterns, see DOC-00040 (Component Authoring).

File naming

  • Components: PascalCase.astro (e.g., HeroSection.astro, PricingCard.astro)
  • Utilities and helpers: kebab-case.ts (e.g., format-date.ts, get-collection.ts)

Ownership markers

Every source file carries a top-of-file ownership comment:

  • // CORE-OWNED — Theme framework. These files are shared across all sites built on the platform. Modify only when changing core behavior.
  • // SITE-OWNED — Per-site customization. These files are specific to an individual client site.

The ownership split follows a split-concern pattern: core defines the schema and default behavior, site provides the instance-specific values. For example, src/core/config/ defines config schemas while src/site/config/ provides the site’s actual configuration.

Key directories

DirectoryOwnershipPurpose
src/core/CORE-OWNEDTheme framework, shared components
src/site/SITE-OWNEDSite config, theme overrides, assets
src/content/SITE-OWNEDContent collections
src/pages/SITE-OWNEDRoute files
src/pages/api/CORE-OWNEDAPI routes (exception to above)
src/lib/CORE-OWNEDUtilities, contracts, helpers

Component sourcing

Components are sourced from a tiered priority list. Only build custom when no tier-1 source fits:

  1. Tailwind Plus Blocks — First choice for layout and section components.
  2. Flowbite — UI components and patterns.
  3. Starwind — Accessible Tailwind-native components and design blocks.
  4. Font Awesome Pro — Icons (manually copied SVGs, not runtime loaded).
  5. Custom — Last resort, when no existing source meets the need.

Hydration policy

The default rendering mode is zero-JS. Pages ship no client-side JavaScript unless explicitly justified.

  • Use vanilla TypeScript for interactive islands that require client-side behavior.
  • Every hydrated component needs an explicit justification — interactivity that cannot be achieved with CSS alone.
  • The project uses Astro’s SSG-first approach with hybrid mode reserved for forms and API routes.

Token usage rules

Components consume semantic tokens (--st-*), never raw color values or primitives (--pt-*). Raw literals are permitted only in approved theme definition files (src/core/styles/ and src/site/styles/).

Tailwind v4 syntax

  • Parenthesis shorthand for token references: bg-(--st-color-surface-soft)
  • Type hints for ambiguous utilities: text-(color:--st-color-text-muted) (distinguishes text color from text size)
  • Multi-variant components use --_* scoped CSS variables, bound per variant in <style> and consumed by utilities in markup

Text sizing defaults

This project re-adds sensible typographic defaults for body text, headings, lists, and other elements after Tailwind’s Preflight reset. Most elements already have an appropriate font size without any utility class. Only add text-size utilities (e.g., text-sm, text-(length:--pt-text-lg)) when you need to override the default — not to restate it. Adding redundant size classes creates maintenance burden and fights the cascade.

Z-index layers

Components that participate in stacking must use the semantic layer contract (--st-layer-* tokens or their bridge utilities like z-dropdown, z-modal-surface). Do not set z-index with raw numeric values, direct primitive --pt-z-* references, or local arithmetic. The complete layer inventory lives in src/core/styles/semantic.css. See Design Tokens — Z-Index Layer Tokens for the naming convention and Component Authoring — Layered UI Contexts for authoring guidance.

What not to do

  • Do not use @apply. It is banned project-wide.
  • Do not reference --pt-* primitives in component markup or styles.
  • Do not use hardcoded color values (#fff, rgb(...), etc.) in components.
  • Do not add text-size utilities that merely restate the element’s default size.
  • Do not set z-index with raw numeric values or local calc() arithmetic — use the semantic layer contract.

Vanilla JS conventions

Interactive components use self-contained vanilla TypeScript with data-slot/data-state attributes, WeakMap instance storage, and astro:page-load lifecycle hooks. See the Vanilla JS Interactivity Patterns guide for full conventions.

Astro template rules

  • Do not wrap <script> tags inside Astro template expressions ({condition && <script>...</script>}). Use an unconditional <script> with a runtime DOM guard instead.
  • Do not add custom data-* attributes to Astro <script> tags — attributes force is:inline mode, which disables TypeScript processing.

Component styling

Tailwind utilities are the primary styling mechanism. The approach layers several patterns:

LayoutSection wrapping

Section components wrap in LayoutSection for consistent vertical spacing and background treatment. Do not apply section-level spacing or background directly — let the layout primitive handle it.

BEM classes as CSS API hooks

BEM-style classes (e.g., .hero__title, .card__body) are retained alongside Tailwind utilities. They serve as stable CSS API hooks that site-level overrides can target in src/site/styles/components.css.

Scoped <style> blocks

Scoped <style> in Astro components is reserved for cases where Tailwind utilities are insufficient:

  • Compound or complex CSS selectors
  • Variant variable binding (--_* scoped variables)
  • data-state visibility overrides and JS-created element styling (:global())

Focus ring pattern

The canonical focus ring for interactive elements:

focus-visible:outline-width-focus focus-visible:outline-focus-ring focus-visible:outline-offset-focus focus-visible:rounded-sm

Apply this pattern consistently to all focusable elements — buttons, links, inputs, and custom interactive widgets.

Accessibility baseline

The project targets WCAG 2.2 AA compliance:

  • Semantic HTML first — use <nav>, <main>, <article>, <button>, etc. Use ARIA only when semantic elements are insufficient.
  • Every interactive element must be keyboard-operable with a visible focus state.
  • Use project primitives (Heading, Button, Icon, Link) over raw HTML elements. These components enforce consistent accessibility patterns.
  • Maintain adequate color contrast ratios in both light and dark modes.
  • Provide meaningful alt text for images and aria labels for icon-only buttons.

PageGridLayout conventions

PageGridLayout is the primary page layout component. Slot usage follows specific rules:

  • slot="subheader" — Hero sections (including compact page-title bands). This slot spans full width below the site header.
  • slot="main-header" — Content metadata, filters, or elements that sit directly above <main> within the content column. Not for page titles.
  • Sidebar slot — Navigation, table of contents, or contextual links.

Markdown heading baseline

For routed content collections (pages, articles, docs):

  • The frontmatter title (or heroTitle override) renders as the page H1.
  • Do not use # headings in body content. Start at ##.
  • # inside fenced code blocks is permitted for examples and comments.

Charter traceability

Every implementation that maps to a charter decision cites it with (§N) notation:

  • In code: JSDoc comments reference the charter section (e.g., /** Token bridge */)
  • In docs and plans: Section headings or inline references (e.g., “Component styling”)

This keeps implementation traceable to the source decision in .docs/charter.md.

Commit and validation workflow

  1. Run validation before committing: Execute npm run validate to run the full quality gate (format check, lint, token lint, content ingestion lint, type checking, build, accessibility checks).
  2. Type checking mid-edit: npx astro check is safe to run at any point during development.
  3. Commit messages: Follow .docs/standards/GIT.md for the required format — structured body with What Changed: and Why: sections.
  4. Production builds: Run npm run build at implementation checkpoints to verify the full build succeeds.

Performance

  • Zero-JS by default. Vanilla TypeScript only for interactive islands that genuinely require client-side behavior (see Hydration policy).
  • Lazy-load images below the fold. Above-the-fold images use eager loading.
  • SSG-first. Server-side rendering is reserved for dynamic routes (API endpoints, form handlers). Static generation handles everything else.
  • Build-time processing over runtime computation. Content transforms, token generation, and data shaping happen at build time.

Anti-patterns to avoid

Anti-patternWhy it’s wrong
Raw color values in component stylesBypasses the token system; breaks theme mode switching and brand consistency.
@apply in stylesheetsProhibited by project convention. Use Tailwind utilities in markup.
Colon-prefixed attribute shorthands (:attr) in Astro template expressionsBreaks Prettier’s Astro parser. Use full-form attributes.
Custom data-* attributes on <script> tagsForces is:inline mode, which disables TypeScript processing.
Wrapping <script> in Astro template expressionsBreaks Prettier. Use unconditional <script> with a runtime DOM guard.
Skipping the Heading component for headingsLoses consistent heading styles and the level-based size cascade.
Installing external component libraries as npm dependenciesThe project adapts patterns, not packages. External deps add bundle weight and coupling.

Design principles

The project follows these core principles consistently:

  • KISS — Prefer the simplest correct solution. Complexity must justify itself.
  • DRY — Factor out repeated logic into shared utilities or components.
  • YAGNI — Don’t build for hypothetical requirements. Build what is needed now.
  • SoC — Separate concerns between layers: core vs site, schema vs instance, layout vs content.
  • SRP — One responsibility per module. If a component does two things, split it.
REQ-00010 normative Client-side JavaScript usage shall be minimized while preserving functional richness.
REQ-00035 normative Components shall use presets rather than ad-hoc values.
REQ-00036 normative Styling decisions shall resolve from tokens or presets.
REQ-00037 normative Utility class usage shall not bypass semantic token constraints.
REQ-00040 normative Components shall resolve styling from semantic design tokens rather than raw color values.
REQ-00046 normative Framework-free components are preferred.
REQ-00081 normative The theme shall conform to WCAG 2.2 Level AA.
REQ-00151 normative Tailwind utility token mappings shall resolve through documented semantic design-token aliases (for example via `@theme` / `@theme inline`) rather than raw palette literals in component/layout code.
REQ-00257 implemented File ownership markers (// CORE-OWNED, // SITE-OWNED) in governed directories shall be validated by a lint step in the validate pipeline, ensuring all core-owned source files declare their ownership zone and site-owned directory files do not carry incorrect markers.
REQ-00265 implemented File ownership marker validation shall apply context-specific defaults for unmarked files: src/site/ and src/components/ are SITE-OWNED by directory (markers recommended but not required); src/pages/ with no marker defaults to SITE-OWNED (fail-safe for site customization files); src/content/ defaults to SITE-OWNED by directory convention. Core-owned directories (src/core/, src/lib/, scripts/) shall require explicit markers.

Search

Search across pages and articles. Use arrow keys to navigate results.

Search across pages and articles.

Loading search...

Search is unavailable. Please try again later.

    No results for ""

    Try different keywords or fewer words.