You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Allow trusted React plugins to add manifest-aware, role-filtered content-list columns without taking ownership of the host table, pagination, or row actions.
Native plugins can extend the admin panel with custom React pages and dashboard widgets — sandboxed plugins describe their UI as [Block Kit](/plugins/creating-plugins/block-kit/) instead, because shipping plugin JavaScript into the admin would break sandbox isolation.
8
+
Native plugins can extend the admin panel with custom React pages, dashboard widgets, field widgets, and content-list columns — sandboxed plugins describe their UI as [Block Kit](/plugins/creating-plugins/block-kit/) instead, because shipping plugin JavaScript into the admin would break sandbox isolation.
9
9
10
10
If your plugin only needs a settings form, the auto-generated `admin.settingsSchema` form (see [Your first native plugin](/plugins/creating-native-plugins/your-first-native-plugin/#settings-ui)) covers most cases without writing any React. Reach for custom components when you need richer UI than `settingsSchema` provides.
11
11
@@ -224,15 +224,53 @@ export function SEOWidget() {
224
224
225
225
Widgets wrap automatically based on screen width.
226
226
227
+
## Content-list columns
228
+
229
+
Trusted React plugins can add read-only columns to active content collection lists. EmDash keeps ownership of the table, pagination, row actions, and loading and empty states; the plugin supplies only the header metadata and cell content.
230
+
231
+
```typescript title="src/admin.tsx"
232
+
importtype {
233
+
ContentListColumnCellContext,
234
+
ContentListColumnExtension,
235
+
} from"@emdash-cms/admin";
236
+
237
+
function ScoreCell({ item }:ContentListColumnCellContext) {
Column ids only need to be unique within the plugin. Contributions are ordered by `order`, then plugin id and column id. A plugin can also provide:
255
+
256
+
-`header`: a custom header component; `label` remains the host-rendered fallback.
257
+
-`collections`: an array or predicate restricting where the column appears.
258
+
-`minRole`: a visibility filter for the admin UI. This is not authorization; plugin API routes must still enforce access.
259
+
260
+
Disabled or missing plugins are omitted. Invalid definitions, collection predicates that throw, and render failures are isolated so the host content list remains usable. Columns are not shown in Trash.
261
+
262
+
Content-list columns are display-only. Server-backed sorting and filtering require a separate host data-provider contract; a browser comparator would only sort the currently loaded cursor pages and is therefore not supported by this API.
263
+
227
264
## Export structure
228
265
229
-
The admin entry point exports two objects:
266
+
The admin entry point exports each contribution directly:
Page paths in `pages` should match the `path` values in `admin.pages`. A trailing slash is treated as equivalent, so `/settings` and `/settings/` resolve to the same page. Opening a plugin at its root resolves to the first registered page. Widget keys must match the `id` values in `admin.widgets`.
291
+
Page paths in `pages` should match the `path` values in `admin.pages`. A trailing slash is treated as equivalent, so `/settings` and `/settings/` resolve to the same page. Opening a plugin at its root resolves to the first registered page. Widget keys must match the `id` values in `admin.widgets`. Content-list columns are discovered directly from the trusted admin entry point and do not need a separate descriptor entry.
250
292
</Aside>
251
293
252
294
## Using admin components
@@ -344,6 +386,7 @@ When a plugin is disabled in the admin:
0 commit comments