Dyrecteddyrected
Admin UI

Admin UI

How the Dyrected admin works, where it can live, and what changes when you embed it.

The @dyrected/admin package is a React-based Admin UI that is automatically generated from your dyrected.config.ts. You define your schema once — the admin renders the forms, tables, media browser, and global editors without any additional code.

There are two ways editors can use it:

  • Hosted admin at app.dyrected.com, managed by Dyrected
  • Embedded admin inside your own app, usually at /admin

That choice is separate from the backend choice. You can use the admin with either a Dyrected Cloud backend or a self-hosted backend.


Embedding the Admin

The Admin UI is a React application exported from @dyrected/admin. Every framework integration is a thin wrapper around one of two primitives:

PrimitiveWhen to use
<AdminUI />You are already in a React tree (Next.js, Vite + React, CRA)
renderAdminUI(el, props)You are outside React (Vue, Nuxt, Svelte, vanilla JS)

Next.js

@dyrected/next wraps <AdminUI /> with server-component guards. Create a catch-all route:

// app/admin/[[...path]]/page.tsx
import { DyrectedAdmin } from "@dyrected/next/admin";

export default function AdminPage() {
  return <DyrectedAdmin />;
}

React (Vite / CRA)

Use <AdminUI /> directly from @dyrected/admin:

// src/pages/Admin.tsx
import { AdminUI } from "@dyrected/admin";

export function AdminPage() {
  return (
    <div style={{ height: "100vh" }}>
      <AdminUI baseUrl={import.meta.env.VITE_DYRECTED_URL} apiKey={import.meta.env.VITE_DYRECTED_API_KEY} />
    </div>
  );
}

Vue 3

@dyrected/vue ships a <DyrectedAdmin /> component that calls renderAdminUI internally. The Admin UI must be client-side only — wrap it in a conditional or use your framework's client-only mechanism:

<!-- src/pages/Admin.vue -->
<script setup lang="ts">
import { DyrectedAdmin } from "@dyrected/vue";
</script>

<template>
  <DyrectedAdmin base-url="https://api.dyrected.cloud" api-key="sk_live_..." />
</template>

Nuxt

@dyrected/nuxt auto-imports <DyrectedAdmin /> globally. Always render it inside <ClientOnly> since the Admin UI requires the browser DOM:

<!-- pages/admin.vue -->
<script setup lang="ts">
definePageMeta({ layout: false });
</script>

<template>
  <ClientOnly>
    <DyrectedAdmin />
  </ClientOnly>
</template>

Svelte / Vanilla JS — renderAdminUI

renderAdminUI(container, props) mounts the Admin UI into any DOM element and returns an unmount function. Use it in any non-React environment:

import { renderAdminUI } from "@dyrected/admin";

const container = document.getElementById("admin-root")!;

const unmount = renderAdminUI(container, {
  baseUrl: "https://api.dyrected.cloud",
  apiKey: "sk_live_...",
});

// To tear down (e.g. on SPA route leave):
// unmount()

Svelte example:

<script>
  import { onMount, onDestroy } from 'svelte'
  import { renderAdminUI } from '@dyrected/admin'

  let container
  let unmount

  onMount(() => {
    unmount = renderAdminUI(container, {
      baseUrl: import.meta.env.VITE_DYRECTED_URL,
      apiKey: import.meta.env.VITE_DYRECTED_API_KEY,
    })
  })

  onDestroy(() => unmount?.())
</script>

<div bind:this={container} style="height: 100vh" />

AdminUI / renderAdminUI Props

Both accept the same props:

Prop

Type


Standalone Components

The admin library also exports specialized components for targeted use cases.

SetupPromptUI

The AI integration prompt can be embedded standalone in your own application if you want to guide users through schema setup without mounting the full dashboard.

import { SetupPromptUI } from "@dyrected/admin";

<SetupPromptUI config={{ baseUrl, apiKey }} />;

Admin UI Pages

Dashboard

The landing page. It is designed as a lightweight editorial workspace rather than an analytics screen.

  • Quick actions: A compact New dropdown for creating documents in editable collections, plus direct actions for upload collections and the first visible global.
  • Recent edits: Shows recently updated documents from editable collections, using admin.useAsTitle when available.
  • Needs attention: Highlights simple setup and content-model issues, such as missing admin.useAsTitle or missing media alt text fields.
  • Setup state: Shows a setup prompt if no collections or globals have been configured yet.

Collection List

A sortable, searchable data table for any collection.

  • Search: The search input queries the field specified by admin.useAsTitle (or the first visible field).
  • Title column: The column for the admin.useAsTitle field (or the first visible field) is rendered as a clickable link that navigates directly to the edit page.
  • Columns: Initial columns are controlled by admin.defaultColumns. Falls back to a sensible set of visible fields and system timestamps. row, join, and unknown column names are ignored automatically.
  • View preferences: Editors reorder or toggle columns using the View button. On the edit page, the same button switches to a drag-to-reorder mode for fields. Preferences are saved personally per editor; admins can also publish a team-wide default using Save for Everyone. See View Preferences.
  • Filters: The filter builder uses a draft/apply flow, so editors can add and edit filter rules before applying them to the list query.
  • Status column: Automatically added if the collection has a status field.
  • Actions: Edit (navigates to edit page), Delete.

Collection Edit / Create

The main content editor. Fields are rendered in the order they appear in your fields array.

  • Sidebar: Shows document ID, created/updated timestamps, and a publishing status panel if the collection has a status field.
  • Live Preview: If admin.previewUrl is set, a split-pane iframe renders alongside the form.
  • Unsaved changes: The browser prompts before leaving if there are unsaved edits.

Media Page

Shown automatically for any collection with upload: true.

  • Grid of uploaded files with thumbnails (images) or file-type icons (documents, videos, etc.)
  • Click to view file details: URL, dimensions, file size, alt text
  • Drag-and-drop upload zone
  • Responsive detail dialog with scrollable metadata and image preview
  • Form-level media pickers use the same grid selection language as the Media Library
  • Delete with confirmation

Global Editor

A single full-page form for editing a Global's fields. Identical to the collection edit form but without list navigation.


The sidebar is generated from your config at runtime:

  1. Grouped collections — Collections sharing the same admin.group value are nested under a labelled, collapsible section.
  2. Ungrouped collections — Appear at the top level in definition order.
  3. Upload collections — Grouped into a "Media" section automatically.
  4. Globals — Listed below collections, also respecting admin.group.
  5. Hidden items — Collections or globals with admin.hidden: true are excluded.

Collections and globals can set admin.icon to a valid Lucide component name such as Newspaper, ShoppingBag, or Palette. TypeScript autocompletes supported names. A configured icon overrides the contextual default used for upload, auth, regular collection, and global navigation items.


Customising Branding

Pass a top-level admin key in your defineConfig to override default styling:

export default defineConfig({
  admin: {
    branding: {
      logo: '/logo.svg',
      logoMark: '/logomark.svg',
      primaryColor: '#6366f1',
      favicon: '/favicon.ico',
    },
    meta: {
      titleSuffix: '— Acme CMS',
    },
  },
  collections: [...],
})

See Admin Config Reference for the full property list.


Custom Field Components

You can replace the default Admin UI widget for any field type or specific field with your own React component:

import { AdminUI } from "@dyrected/admin";
import { MyMapPicker } from "./components/MyMapPicker";
import { MyColorPicker } from "./components/MyColorPicker";

<AdminUI
  baseUrl="..."
  apiKey="..."
  components={{
    fields: {
      // Replace ALL fields of type 'json' with your component
      json: MyCodeEditor,
      // Or target a specific field by name (takes precedence over type)
      "products.locationCoords": MyMapPicker,
      "settings.brandColor": MyColorPicker,
    },
  }}
/>;

Custom Component Props

Your component receives:

Prop

Type


Field Type → Admin Component Mapping

Field TypeAdmin ComponentNotes
textText input
textareaTextareaAuto-expanding
richTextTiptap editorBlock-based, floating toolbar
numberNumber input
booleanCheckboxUse admin.layout: 'switch' for switch rendering
dateCalendar picker
selectDropdownSupports admin.layout: 'radio' for radio button rendering
multiSelectTag-based multi-select
emailEmail inputClient-side format validation
urlURL inputWith "Open in new tab" button
iconIcon picker popoverSearchable grid of all Lucide icons; stores icon name as string
relationshipSearchable comboboxThumbnail grid for upload collections
joinRead-only related-docs listVirtual field — no data stored; shows docs from another collection that reference this one
arrayExpandable card listDrag-to-reorder, duplicate, move, and delete
objectGrouped field panelCollapsible
jsonCode editorJSON syntax highlighting
blocksBlock picker + inline editorOne editor per block type
rowFlex row containerVirtual layout field — arranges children side-by-side; no data stored

On this page