Pikbase Docs
Open console (opens the console)
Esc

Type to search.

Data and schema

Generate forms from definitions

Build schema-driven React forms with GsbForm, customize fields, and save through authorized backend operations.

Use GsbForm from @gsb-core/react-forms to render a form from an installed entity definition. The definition supplies the properties, data types, references, labels, ordering, and form visibility metadata. Your React application supplies the surrounding screen and the authorized operation that saves submitted values.

This is runtime React form generation, not a visual application designer or a command that generates source files. It does not install backend definitions or grant access. Start with a workspace-bound React app and read schema design before changing the underlying model.

Prerequisites

Run inside your application's established workspace client and authentication setup. Definition loading, record loading, reference pickers, and uniqueness checks use the configured Core services. Installing the React package alone does not configure them. Use the selected workspace's real definition name or id and verify the signed-in user can read it and perform the intended operation.

For an existing React application, add the package with pnpm if it is not already a direct dependency:

pnpm add @gsb-core/react-forms

Keep compatible Core and React package versions and the generated lockfile. The boilerplate guide explains workspace binding and frontend composition.

Create a record

This component accepts a save operation from its owning screen. Replace Customer with an installed definition. The saveCustomer callback must call the established Entity Service integration; it is not local persistence or a simulated backend.

import { GsbForm, type FormValues } from "@gsb-core/react-forms";

interface CustomerCreateFormProps {
  saveCustomer: (values: FormValues) => Promise<void>;
}

export function CustomerCreateForm({
  saveCustomer,
}: CustomerCreateFormProps) {
  return (
    <GsbForm
      entityDefName="Customer"
      formMode="create"
      submitButtonText="Create customer"
      onSubmit={saveCustomer}
    />
  );
}

Submitting does not automatically save a record. onSubmit receives validated form values. Await the authorized save inside that callback, propagate failures, and only show success or navigate after persistence succeeds. See working with entity data for the save contract. Supplying onChange observes draft values; it does not save them either.

View and update records

Use entityId to load an existing record. For example, a read-only detail screen can render:

import { GsbForm } from "@gsb-core/react-forms";

export function CustomerDetails({ customerId }: { customerId: string }) {
  return (
    <GsbForm
      key={customerId}
      entityDefName="Customer"
      entityId={customerId}
      formMode="view"
      showSubmitButton={false}
    />
  );
}

For editing, use formMode="update" and pass an onSubmit callback that saves against the selected record's identity. A record id is selection input, not authorization. When switching between records or workspaces in the same screen, remount the form with a key that changes with that context so loaded state is not reused accidentally.

Mode Purpose Persistence
create Build a new record using create-mode schema metadata. Your onSubmit callback creates it.
view Display an existing record read-only. No write is needed; hide the submit button.
update Edit an existing record using update-mode metadata. Your onSubmit callback saves the selected record.

You can also supply an already loaded entityDef and entity instead of asking the form to fetch them. Prefer that approach when the owning screen already has the authorized definition and record. Do not supply conflicting identifiers and values.

Customize the generated form

Keep shared field rules in the entity definition. Use component props for a particular screen's presentation, not as substitutes for server permissions.

Prop Effect
excludeFields Omits named properties from this form.
readOnlyFields Makes named properties read-only in this screen.
requiredFields Adds required-field checks for named properties.
includeSystemFields Includes system properties normally excluded; defaults to false.
showGroups Displays schema-derived field groups; defaults to true.
showSubmitButton, submitButtonText Controls the built-in submit control.
readOnly, isLoading Applies screen-level read-only or loading state.
onLoad Receives the generated FormConfig.
onCancel Handles the cancel action when provided.
controlOverrides Selects a supported control kind for a named property.
registry Supplies control components for supported control kinds.

For deeper control customization, use the exported createControlRegistry API and the package's typed control contracts. A custom control must preserve value changes, validation feedback, and read-only behavior. Do not duplicate the record's business rules in a custom input.

Validation and permissions

The form derives validation from its generated field configuration and checks unique fields before invoking onSubmit. Backend validation and authorization remain authoritative: another caller can bypass the UI, and concurrent writes can invalidate a client-side uniqueness result. A hidden or read-only field is not a security rule.

Use authentication and workspace access for the authorization boundary. Never put credentials in props intended for display, URLs, browser storage, or VITE_* configuration, and do not log submitted personal data.

Troubleshoot and verify

If the form cannot load, inspect the selected workspace, definition name, record id, and caller permissions. If a field is missing, inspect system-field exclusion, excludeFields, form-mode and screen visibility metadata, and reference targets. Do not replace missing definitions or inaccessible records with fake schema or data.

Verify create, view, and update separately. Check required fields, references, read-only fields, invalid values, and save failures. After a successful save, reload and read the record through Entity Service to prove persistence. Also switch records and workspace contexts to confirm the screen does not retain another context's values.

Existing FormGenerator integrations

FormGenerator remains a compatibility entry point and delegates to GsbForm. New code should use GsbForm. The older fieldRenderers map belongs to that compatibility wrapper; use registry and controlOverrides with GsbForm rather than copying the old renderer pattern into new screens.

Contract sourcedocs/guides/form-generation.md + @gsb-core/react-forms