Skip to Content
Prism UI
Core Concepts

Registry System

How defineRegistry works, and why it's consumer-owned rather than global.

defineRegistry

function defineRegistry<const TRegistry extends FieldRegistry>(
  entries: TRegistry,
): Readonly<TRegistry>;

A registry maps a field-type name to the field component that renders it:

import { defineRegistry } from '@prismrepo/forms';
import { TextField } from './text-field';
import { NumberField } from './number-field';

export const registry = defineRegistry({
  text: TextField,
  number: NumberField,
});

defineRegistry is a plain identity function: it returns the same value you passed in, as Readonly, with no module-level registration side effect. There's no global registry anywhere in Prism to import from, you create your own and pass it where it's needed.

Why consumer-owned, not global

Two registries created from two separate defineRegistry calls are fully independent, they never share configuration, and a const TRegistry built from one is never interchangeable with one from the other, even if they happen to declare the same key names. This matters for:

  • Multiple apps or test suites in one process never observing each other's field configuration through shared module state.
  • Compile-time type safety. const TRegistry extends FieldRegistry preserves each registered field-type name as its own literal string type, not widened to string, which is what lets createFormBuilder reject invalid or typo'd field-type names at compile time.

How a registered type gets resolved

resolveFieldComponent(registry, type) resolves a configured field type to its component at the point of use, never via a static import. <PrismField> calls this internally. If type isn't a key in registry, it throws PrismConfigurationError naming the field and the registry's known types, rather than silently rendering nothing, this is the runtime half of a check the type system already makes a compile-time error for literal configuration (relevant when a field's type came from data the type checker couldn't see, for example parsed JSON).

Extending a registry as your app grows

A registry is just an object literal. Add a new field type by adding a new key:

export const registry = defineRegistry({
  text: TextField,
  number: NumberField,
  rating: RatingField, // a custom, consumer-authored field component
});

There is no distinction the type system enforces between a field component Prism's CLI installed and one you wrote yourself, see Custom Fields.

On this page