A plugin for EmDash CMS that provides composable field widgets for json fields. It replaces the default plain text input with rich editing UIs configured entirely through seed options — no React code needed from site builders.
seed field definition ("widget": "field-kit:grid", "options": { ... })
→ EmDash splits on ":" → plugin "field-kit", widget "grid"
→ loads adminEntry (src/admin.tsx)
→ looks up fields["grid"] → Grid component
→ renders <Grid value={...} onChange={...} options={...} />
Three layers connect seed config to rendered UI:
-
Plugin descriptor (
src/index.ts) —fieldKitPlugin()returns aPluginDescriptorwithadminEntrypointing to the component file.createPlugin()/definePlugin()registers widget names and their compatible field types. -
Component map (
src/admin.tsx) — exportsfieldsobject mapping widget names to React components. EmDash looks up the widget name here at render time. -
Widget components (
src/widgets/*.tsx) — each receivesFieldWidgetProps(value,onChange,label,id,required,options,minimal) and renders the editing UI. All widget-specific config comes fromoptions.
| File | Purpose |
|---|---|
src/index.ts |
Plugin descriptor + widget registration via definePlugin() |
src/admin.tsx |
Component map — maps widget names to React components |
src/widgets/object-form.tsx |
Inline form for flat JSON objects |
src/widgets/list.tsx |
Ordered array editor with add/remove/reorder |
src/widgets/grid.tsx |
Rows × columns matrix (toggle, text, number, select cells) |
src/widgets/tags.tsx |
Free-form tag/chip input for string arrays |
src/shared/sub-field.tsx |
Shared sub-field renderer (8 input types), used by object-form and list |
src/shared/types.ts |
TypeScript interfaces: FieldWidgetProps, SubFieldDef, GridAxisDef |
src/shared/utils.ts |
Data normalization (object, array, grid with legacy format migration, tags) and mustache summary renderer |
- Create
src/widgets/<name>.tsx— export a component acceptingFieldWidgetProps - Add
{ name: "<name>", label: "...", fieldTypes: [...] }tofieldWidgetsinsrc/index.ts - Add
"<name>": Componentto thefieldsmap insrc/admin.tsx
- Styling: Tailwind utility classes matching EmDash's admin design system (
border-input,bg-muted,text-muted-foreground, etc.). No custom CSS. - Data normalization: Every widget normalizes incoming
valuedefensively (handlesundefined, wrong types, legacy formats). Normalization functions live insrc/shared/utils.ts. - No nesting: Sub-fields are flat primitives (text, number, boolean, select, textarea, date, color, url). For deeper structures, use multiple
jsonfields or Portable Text. - Refs for callbacks: Widgets use
useRefto hold current data souseCallbackclosures don't go stale.
emdash— providesdefinePlugin,PluginDescriptor, and the admin rendering hostreact18 or 19
v0.1 — Tier 1 widgets (object-form, list, grid, tags) are implemented. Tier 2 (color, slider, rating, date-range) is planned but not yet built. No tests yet.