Overview
Swap your own React (or Vue) components into the admin at two extension points — field inputs and dashboard/list slots — and know where the boundaries are.
The admin is generated from your schema, but you're not stuck with the built-in look of every piece. Dyrected gives you two clean extension points: you can replace a field's input with your own component, and you can inject components into slots on the dashboard and collection lists. This page is the map — it explains both mechanisms, shows the registration pattern they share, and is honest about what you can't customize this way.
Throughout, "your app" means the project you embedded the admin into — your Next.js, Nuxt, Vue, or React application.
The mental model
Every custom component follows the same two-step pattern: declare where it goes, then provide the component.
- You reference a component by a string key — either on a field (
admin.component) or in a slot list (admin.components) in your schema. - You pass the actual component under that same key in the
componentsprop of<DyrectedAdmin>.
There's no import map, no build step, and no string module paths. You hand real component references to the admin, and it renders them where your config said to. If a key has no matching component, the admin skips it (and warns in development); if a custom component throws, an error boundary isolates it so the rest of the admin keeps working.
There are exactly two extension points:
- Custom field components — replace the input for a specific field.
- Component slots — inject components into fixed positions on the dashboard and collection lists.
Custom field components
When a field needs an input the built-in set doesn't cover — a color picker, a map, a code editor — point the field at your own component. Set admin.component to a key of your choosing on the field:
export const Products = defineCollection({
slug: "products",
fields: [
{
name: "brandColor",
label: "Brand color",
type: "text",
admin: {
component: "brand-color-picker",
description: "Brand hex color, e.g. #6366f1",
},
},
],
});Then register the component under the same key in the components.fields map when you mount the admin:
import { DyrectedAdmin } from "@dyrected/next/admin";
import { BrandColorPicker } from "./BrandColorPicker";
export default function AdminPage() {
return (
<DyrectedAdmin
components={{
fields: { "brand-color-picker": BrandColorPicker },
}}
/>
);
}The key is yours to name — it's matched by the admin.component string, not by field type. That means a custom component applies to the specific field (or fields) that opt into it, not to every field of a given type.
What your component receives
Your field component is handed everything it needs to read and write the value, plus context about where it's rendering:
| Prop | What it is |
|---|---|
value | The current field value |
onChange | Call it with the new value to update the form |
field | The field's schema definition from your config |
path | The field's name |
disabled | true when the field is read-only or the user lacks update access |
collection | The slug of the collection the field belongs to |
context | { user, schemas, siblingData } — the current user, all loaded schemas, and the sibling field values in the same document |
Read from value, call onChange to update, and use context.siblingData if your input depends on other fields. Because the admin resolves access before rendering, honoring disabled is usually all you need for permissions.
Component slots
Slots are fixed positions where you can add components without rebuilding a whole screen — a banner above the dashboard, a header above a collection list, a widget after a table. They use the same declare-then-provide pattern, but you declare them in an admin.components object rather than on a field.
Declare the slot keys in config — on defineConfig for the dashboard, or on a collection for its list:
export const Posts = defineCollection({
slug: "posts",
admin: {
components: {
beforeList: ["posts-header"],
},
},
fields: [...],
});
export default defineConfig({
collections: [Posts],
admin: {
components: {
beforeDashboard: ["welcome-banner"],
},
},
});Then register the components, grouped by where they live:
<DyrectedAdmin
components={{
dashboard: { "welcome-banner": WelcomeBanner },
collectionList: { "posts-header": PostsHeader },
}}
/>Each slot list is an array, so you can stack more than one component in a slot. The two slot groups get different props suited to where they render — the dashboard slots receive the client, user, and schemas; the list slots also receive the collection, its documents, pagination, and permissions. Each group has its own page:
- Dashboard — the
beforeDashboard/afterDashboardslots and their props. - List View — the
beforeList/beforeListTable/afterListTable/afterListslots and their props.
Using Vue components
If your app is Vue or Nuxt, you register Vue components exactly the same way — pass them in the components prop. The Vue integration wraps them automatically so they render inside the React-based admin; you don't do anything special beyond passing them. The props described above arrive as Vue props.
What you can't customize this way
It's worth being clear about the edges so you don't go looking for something that isn't there. These two extension points — field components and dashboard/list slots — are the whole surface today. Dyrected does not currently support:
- Replacing root-level UI (the navigation, header, login screen, or logo as a component — the logo is set with branding config, not a component).
- Injecting custom React context providers around the admin.
- Replacing or adding whole views (a custom edit view, document tabs, custom routes, or a full list-view replacement).
If your goal is theming rather than swapping components, that's Customizing CSS. If you need one of the unsupported customizations above, it's a genuine gap — raise it rather than working around it.
Recommended path
Reach for a custom field component when a specific field needs an input the defaults don't offer, and a slot when you want to add something alongside the built-in dashboard or list without rebuilding it. Start from this page's pattern — declare a key, register the component — then go to the Dashboard or List View page for the exact props your slot receives.
Customizing CSS
Match the admin to your brand with a few config options, then reach for CSS variables when you need full control of the theme, in light and dark mode.
Dashboard
Add your own components above and below the built-in dashboard — a welcome banner, an analytics widget, a shortcut panel — using the dashboard slots.