docs/docs/en/plugin-development/client/examples/custom-field.md
In NocoBase, field components are used to display and edit data in tables and forms. This example demonstrates how to build a custom field display component using ClickableFieldModel -- adding square brackets [] around the field value, and binding it to the input type field interface.
:::tip Prerequisites
It's recommended to familiarize yourself with the following content for a smoother development experience:
load() lifecycletExpr() deferred translation usage:::
We're building a custom field display component:
ClickableFieldModel with custom rendering logic[]input (single-line text) field type via bindModelToInterfaceAfter enabling the plugin, find a single-line text field column in a table block, click the column's configuration button, and you'll see the DisplaySimpleFieldModel option in the "Field Component" dropdown menu. After switching to it, the column's values will display in [value] format.
Full source code is available at @nocobase-example/plugin-field-simple. If you want to run it locally:
yarn pm enable @nocobase-example/plugin-field-simple
Let's build this plugin step by step from scratch.
Run the following in the repository root:
yarn pm create @my-project/plugin-field-simple
For detailed instructions, see Writing Your First Plugin.
Create src/client-v2/models/DisplaySimpleFieldModel.tsx. This is the core of the plugin -- defining how the field renders and which field interface it binds to.
// src/client-v2/models/DisplaySimpleFieldModel.tsx
import React from 'react';
import { ClickableFieldModel } from '@nocobase/client-v2';
import { DisplayItemModel } from '@nocobase/flow-engine';
import { tExpr } from '../locale';
export class DisplaySimpleFieldModel extends ClickableFieldModel {
public renderComponent(value: string) {
// this.context.record gives you the complete record of the current row
console.log('Current record:', this.context.record);
console.log('Current record index:', this.context.recordIndex);
return <span>[{value}]</span>;
}
}
// Set the display name in the "Field Component" dropdown menu
DisplaySimpleFieldModel.define({
label: tExpr('Simple field'),
});
// Bind to the 'input' (single-line text) field interface type
DisplayItemModel.bindModelToInterface('DisplaySimpleFieldModel', ['input']);
Key points:
renderComponent(value) -- Receives the current field's value as a parameter and returns the rendered JSXthis.context.record -- Gets the complete data record of the current rowthis.context.recordIndex -- Gets the index of the current rowClickableFieldModel -- Extends FieldModel with click interaction capabilitiesdefine({ label }) -- Sets the display name in the "Field Component" dropdown menu; without it, the class name would be displayed directlyDisplayItemModel.bindModelToInterface() -- Binds the field model to specified field interface types (e.g., input for single-line text fields), making this display component selectable for fields of that typeEdit the translation files under the plugin's src/locale/, adding translations for all keys used by tExpr():
// src/locale/zh-CN.json
{
"Simple field": "简单字段"
}
// src/locale/en-US.json
{
"Simple field": "Simple field"
}
:::warning Note
Adding language files for the first time requires restarting the application to take effect.
:::
For more about translation file conventions and tExpr() usage, see i18n Internationalization.
Edit src/client-v2/plugin.tsx to lazy-load the model via registerModelLoaders:
// src/client-v2/plugin.tsx
import { Plugin } from '@nocobase/client-v2';
export class PluginFieldSimpleClient extends Plugin {
async load() {
this.flowEngine.registerModelLoaders({
DisplaySimpleFieldModel: {
loader: () => import('./models/DisplaySimpleFieldModel'),
},
});
}
}
export default PluginFieldSimpleClient;
yarn pm enable @my-project/plugin-field-simple
After enabling, find a single-line text field column in a table block, click the column's configuration button, and switch to this custom display component in the "Field Component" dropdown menu.
Capabilities used in this example:
| Capability | Usage | Documentation |
|---|---|---|
| Field Rendering | ClickableFieldModel + renderComponent(value) | FlowEngine -> Field Extension |
| Bind Field Interface | DisplayItemModel.bindModelToInterface() | FlowEngine -> Field Extension |
| Model Registration | this.flowEngine.registerModelLoaders() | Plugin |