Alinea’s field system is open for extension. When none of the built-in fields fit your use case you can define a custom field that integrates seamlessly with the dashboard editor and the query layer. Every custom field has two parts: a field definition that describes the TypeScript value type and its options, and a view component — a React component rendered in the dashboard when an editor opens an entry that uses the field.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/alineacms/alinea/llms.txt
Use this file to discover all available pages before exploring further.
The view component is only loaded in the dashboard bundle. It is never included in your Next.js application bundle or in the query layer. Alinea loads view modules lazily by their import path string, so only editors pay the cost of the dashboard UI code.
Architecture overview
| Part | Where it lives | What it does |
|---|---|---|
Field definition (.ts) | Anywhere in your project | Calls Field.create(...) and exports the factory function and type alias |
View component (.view.tsx) | Same directory, separate file | Exports a named React component that Alinea mounts in the dashboard |
Real-world example: PositionField
The following example is taken directly from the Alinea development workspace. It implements aposition field that stores {x, y} coordinates as fractions of a 2D area — picked by clicking on an interactive map.
The field definition
PositionField.ts
- Declare a type alias using
Field.Create<YourValueType>. This is the TypeScript type that content queries will resolve to. - Export a factory function that calls
Field.create(config). - Reference the view component by a module path string in the format
"modulePath#ExportName". Alinea resolves this path at dashboard load time.
Field.create options
The label passed by the caller — forward it from the factory function’s first argument.
The options object passed by the caller. Use
Field.Options<YourFieldType> to get the correct TypeScript type including all standard base options (required, readOnly, hidden, shared, initialValue, validate).A module path and export name in the format
"path/to/module#ExportedComponentName". The path is resolved relative to the root of your project (or as configured in your tsconfig paths or bundler aliases).The view component
PositionField.view.tsx
useField
useField(field) is imported from alinea/dashboard and is the primary hook for custom field views. It returns:
| Property | Type | Description |
|---|---|---|
label | string | The field’s label, resolved from options |
options | Options | The full options object (including readOnly, required, etc.) |
value | YourValueType | The current stored value |
mutator | (value: YourValueType) => void | Call this to update the field value |
error | string | undefined | Validation error message, if any |
fieldKey | string | The key of this field in its parent form |
InputLabel
Wrap your custom input in<InputLabel label={label}> (also from alinea/dashboard) to get consistent label rendering, error display, and help text that matches the built-in fields.
Using a custom field in a type definition
Once you have defined your field, use it exactly like any built-in field:Using the custom field in a content type
position field accepts all standard base options (required, readOnly, hidden, shared, initialValue, validate) in addition to any options you define in its options type.
Registering the view with bundler aliases
If your project uses TypeScript path aliases (e.g.@/ mapping to src/), make sure the view path in view: '@/field/PositionField.view#PositionInput' matches your tsconfig and/or bundler configuration. Alinea resolves view paths using the same module resolution as your dashboard bundle.
Summary
- Create a
.tsfile that callsField.create({label, options, view})and exports a factory function and type alias. - Create a
.view.tsxfile that exports a named React component accepting{field: YourFieldType}. - Use
useField(field)inside the component to access the current value and write updates via themutator. - Reference the view with a
"path#ExportName"string that your bundler can resolve. - Use your factory function exactly like any built-in
Field.*factory insideConfig.documentorConfig.type.