Skip to main content
Version: 1.4.0
Last Updated: 2026-06-02
Status: Active
Owning Module: PF (Platform Foundation)
Note: This guide is the single canonical reference for all settings page patterns.

Overview

This guide documents the standardized pattern for module settings pages across all cores. All settings pages should use shared components for consistency and maintainability. For current Platform Settings module surfaces (hub/routes/exports), also see:
  • src/platform/settings/README.md
  • src/platform/settings/pages/data-migration/README.md

Architecture

Platform Settings Hub Integration Checklist

When adding a new platform settings page (/settings/*):
  1. Add the lazy route in src/routes/platform.tsx.
  2. Add/verify the correct RequirePermission(...) guard.
  3. Add a Settings Hub card (if it should be user-discoverable from /settings).
  4. Keep card visibility and route permission checks aligned.
  5. Confirm loading and error states use shared settings components.
This prevents route/hub drift and permission mismatch regressions.

Quick Start

Notes
  • Prefer PageContainer / SettingsPageLayout instead of container mx-auto.
  • Include docsPath on every SettingsPageHeader so the docs link is consistent.
  • Wire isDirty from your form (react-hook-form formState.isDirty) when you enable the unsaved navigation guard.
  • Call transformSettingsForDb in module upsert hooks or submit handlers before writing nullable columns.
  • Run npm run audit:settings-consistency when changing settings routes or page shells.

Component Reference

SettingsPageHeader

Located at @/platform/settings/components/SettingsPageHeader Provides a standardized header with:
  • Module icon
  • Title and description
  • Optional documentation link
Props: Legacy Interface (also supported):

SettingsLoadingSkeleton

Located at @/platform/settings/components/SettingsLoadingSkeleton Provides a loading skeleton that matches the settings page layout:
Props: Renders:
  • Header skeleton (title + description)
  • Tab bar skeleton (if using tabs)
  • Form field skeletons

SettingsErrorState

Error display with retry option.

Settings Hook Pattern

Each module should have a standardized settings hook. The recommended pattern uses a single upsert mutation for simplicity and consistency. The preferred pattern uses a single upsert mutation (as seen in LO, RH, and all other modules):

Upsert Hook Return Interface

All module settings hooks now return a consistent interface:

Settings Page Usage

With the upsert pattern, settings pages are simplified:

Legacy Pattern (Update-based)

For reference, the older update-based pattern is still supported but not recommended for new implementations:

Mobile Responsiveness

Settings pages must be mobile-responsive:

Desktop (md+)

  • Full tab bar visible via ScrollableTabsList
  • Side-by-side form layouts where appropriate

Mobile (< md)

  • ScrollableTabsList horizontally scrolls; no second Select dropdown needed
  • Single-column form layouts
  • Touch-friendly inputs (44px minimum)
Do NOT use a TabsList/Select split for mobile. ScrollableTabsList handles all viewport sizes with horizontal scroll and touch-swipe. Using TabsList directly or a manual Select fallback breaks the tab URL-sync pattern and violates the accessibility requirement (aria-label on ScrollableTabsList).

Form Organization

Tab Structure

Organize settings into logical tabs:

Form Layout

Dirty State Management

Track unsaved changes:

Module Compliance Status

All modules now use the standardized upsert pattern:

Existing Implementations

Reference these for patterns:

Best Practices

  1. Never return null for loading states - Always use SettingsLoadingSkeleton
  2. Always include docsPath - Link to relevant admin documentation
  3. Use semantic icons - Choose icons that represent the module
  4. Handle no-organization state - Show a helpful message
  5. Use consistent card structure - CardHeader with title/description, CardContent with form
  6. Use upsert pattern - All modules now use this pattern for consistency
  7. Always use shared components - Don’t create custom headers/skeletons
  8. Handle all states - Loading, error, empty, success
  9. Validate before save - Use form validation
  10. Show save confirmation - Toast on success
  11. Warn on unsaved changes - Block navigation if dirty
  12. Keep tabs focused - 3-5 settings per section max
  13. Use appropriate inputs - Switch for boolean, Select for enum