| title | Field Registry |
|---|
Object UI uses a Field Registry system to decouple the core engine from specific UI implementations of fields. This allows for rich extensibility and plugin support.
The @object-ui/fields package serves as the "Universal Language" for rendering values.
When a component like <ObjectGrid> needs to render a date field, it doesn't import a DatePicker directly. Instead, it asks the registry:
"Hey, give me the component responsible for rendering type 'date'."
This architecture allows you to:
- Override standard fields (e.g. replace the native date picker with a fancy one).
- Add new field types (e.g. add a
ratingorsignaturefield). - Keep bundles small (heavy components like Code Editors are loaded only if their plugin is registered).
You can register a custom renderer globally, typically at your app's entry point.
// src/setup.tsx
import { registerFieldRenderer, type CellRendererProps } from '@object-ui/fields';
const MyRatingField = ({ value, onChange }: CellRendererProps) => {
return (
<div className="rating">
{[1, 2, 3, 4, 5].map(star => (
<span
key={star}
onClick={() => onChange(star)}
style={{ color: star <= value ? 'gold' : 'grey' }}
>
★
</span>
))}
</div>
);
};
// Register it
registerFieldRenderer('rating', MyRatingField);Once registered, you can simply use the new type in your JSON schema.
{
"type": "form",
"fields": [
{
"name": "customer_satisfaction",
"type": "rating",
"label": "Satisfaction"
}
]
}Object UI comes with built-in support for the standard ObjectStack Protocol types:
| Type | Description |
|---|---|
text |
Single line text |
textarea |
Multi-line text |
number |
Numeric input |
currency |
Currency formatting |
percent |
Percentage values |
date |
Date picker |
datetime |
Date & Time picker |
boolean |
Checkbox / Switch |
select |
Dropdown |
lookup |
Reference to another object |
master_detail |
Parent-child relationship |
user |
Person picker — searches the sys_user object (a lookup specialized to users) |
owner |
Record owner — a user field, typically read-only and stamped with the current user |
If you are building your own custom component (like a Kanban board card), you can leverage the registry to render fields without reinventing the wheel.
import { getCellRenderer } from '@object-ui/fields';
export const KanbanCard = ({ task }) => {
// Get the standard renderer for a 'user' type field
const UserRenderer = getCellRenderer('user');
return (
<div className="card">
<h3>{task.name}</h3>
<div className="assignee">
<UserRenderer
value={task.assignee}
field={{ type: 'user' }}
/>
</div>
</div>
);
};