Interface

The Interface page controls the form used to create, view, and update a single record. In practice, this is the collection's form_codeblock.

Under the hood
Record interfaces are authored with the Dynamic UI SDK. Read the SDK guide for the supported components and authoring patterns.

Auto-generated Forms

If a collection does not yet have a form codeblock, Database Studio can generate a starter layout from the schema for you. This is the fastest way to get to a usable baseline.

That generated layout is then stored as the collection's form codeblock and can be edited like any other Dynamic UI form.

Generation is a setup action, not a runtime fallback
If no form codeblock is configured, the runtime does not silently build one for end users on every request. Generate and save the starter form before you rely on the interface in production.

Custom Forms (form_codeblock)

Move to a custom form when the generated layout is not enough. Common reasons include:

  • You need better grouping, tabs, or layout.
  • You want to hide or emphasize fields based on context.
  • You need richer collection-aware components such as grids or tabs inside the form.
import { Params, ReturnType } from './data';
import { SDK } from './external';

export function run(params: Params): ReturnType {
	return SDK.GlobalStore({
		form_for: 'projects',
		data: {
			ui: {
				activeTab: 'summary'
			}
		},
		ui: (store) => (
			<tabs value={store.bind('data.ui.activeTab')}>
				<tabcontent value="summary" label="Summary">
					<flex direction="column" gap={3}>
						<forminput label="Project name" value={store.bind('form.name')} />
						<forminput label="Status" value={store.bind('form.status')} />
						<formbutton label="Save changes" action="submit" />
					</flex>
				</tabcontent>
			</tabs>
		)
	});
}

Binding Rules

A form interface is collection-backed, so the important rule is to bind editable fields to form.* paths using store.bind(...).

  • Use store.bind('form.field_name') for editable collection fields.
  • Use store.read(...) for display-only values.
  • Use store.derive(...) for computed form values when needed.
FormInput is metadata-driven
You do not choose the input renderer with a custom type prop in the form code. Norbital resolves the field control from the bound collection column and form metadata.

CEL Expressions

Within a form, CEL is best used for lightweight conditions and derived display behavior, such as:

  • showing a section only when a status changes,
  • computing a derived value for display,
  • driving tab or step visibility from the current form state.

Render Modes

The same interface definition is reused across create, view, and update contexts, so you normally maintain one form for the collection rather than three separate versions.

How Redaction Affects Interfaces

Interfaces remain permission-aware. If a user cannot access a field, the system can redact the corresponding node and remove restricted fields from the submitted payload.

  1. Generate the starter form from the schema.
  2. Improve readability with grouping and tabs.
  3. Introduce CEL and richer Dynamic UI behavior only where it helps the workflow.
  4. Test the form with the real team permissions that will use it.