Skip to content

Dashboard Guide

ACMS includes an optional self-hosted dashboard for visual content editing. The dashboard is a Next.js application that connects to the ACMS dev server and provides a modern UI for managing your content fields.

The dashboard is entirely optional — you can always edit acms.json directly, use the REST API, or build a custom UI.

The dashboard provides:

  • Visual editors for all field types (string, text, number, boolean, array)
  • Field type management — change a field’s type via the metadata system
  • Field creation and deletion
  • Real-time updates via Server-Sent Events (SSE)
  • Fields organized by top-level groups (e.g., hero.*, contact.*)
  • Search and filtering

The dashboard connects to the ACMS dev server. Start both:

Terminal window
# Terminal 1: Start ACMS dev server
acms dev
# Terminal 2: Start the dashboard
pnpm dev --filter dashboard

Visit http://localhost:3002 to open the dashboard.

The dashboard is designed to be a standalone, clonable project. You can copy it, customize it, and deploy it independently from your main application.

The dashboard provides type-specific editors for each field:

Single-line text input for short content like titles, labels, and names.

Multi-line textarea for longer content like descriptions, paragraphs, and body copy.

Numeric input with validation. Prevents non-numeric input.

Toggle switch for true/false values like feature flags, visibility toggles, and settings.

List editor with:

  • Add — Append new items to the array
  • Remove — Delete individual items
  • Reorder — Drag to reorder items in the list

Each field displays a type badge (e.g., “string”, “text”, “number”). Click the badge to change the field’s type. The type determines which editor is shown and how the value is validated.

Available types:

TypeDescription
stringShort text, single line
textLong text, multi-line
numberNumeric values
booleanTrue or false
arrayOrdered list of items
objectNested field group
imageImage URL with preview

Use the “Add Field” form to create new fields:

  1. Enter the field path (e.g., hero.ctaText)
  2. Select a field type
  3. Optionally set an initial value
  4. Click “Create”

The field is added to acms.json and appears in the dashboard immediately.

Click the delete button on any field to remove it. A confirmation dialog prevents accidental deletions. Deleting a field removes both its value and metadata from acms.json.

The dashboard uses Server-Sent Events (SSE) to stay in sync with the dev server. When acms.json changes (from any source — direct editing, API calls, or another dashboard tab), all connected dashboards update automatically.

This means:

  • Multiple team members can edit simultaneously
  • Changes from code (field registration) appear instantly
  • External edits to acms.json are reflected in real-time

Fields are organized by their top-level key. For example:

hero
├── title: "Welcome to ACMS"
├── subtitle: "Schema-less CMS"
└── ctaText: "Get Started"
contact
├── email: "hello@example.com"
└── phone: "+1 234 567 890"
name: "My Site"

Top-level fields (like name) appear in an ungrouped section.

Use the search bar to filter fields by path or value. Searching for “hero” shows all fields under the hero group. Searching for “email” shows any field whose path or value contains “email”.

The reference dashboard implementation uses:

  • Next.js 16 with React 19
  • shadcn/ui with base-ui components
  • Tailwind CSS 4 for styling
  • Noto Sans font
  • Server-Sent Events for live updates

If the reference dashboard doesn’t meet your needs, you can build a custom editing UI using the REST API. All CRUD operations are available:

// Fetch all fields
const schema = await fetch('http://localhost:3001/api/schema').then(r => r.json());
// Update a field
await fetch('http://localhost:3001/api/field', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ path: 'hero.title', value: 'New Title' }),
});
// Subscribe to updates
const events = new EventSource('http://localhost:3001/api/events');
events.addEventListener('schema-update', () => {
// Refetch schema
});