Portal Community

PlayerRegistryEntry Type

// packages/player-registry/src/types.ts

interface PlayerRegistryEntry {
  /** Unique identifier — used in schema metadata.playerOverride */
  id:          string;

  /** Human-readable name shown in Atlas Forms Studio */
  label:       string;

  /** Optional description shown in the Studio player picker tooltip */
  description?: string;

  /** The React component that renders the form */
  component:   React.ComponentType<FormPlayerProps>;

  /** Optional thumbnail URL shown in Studio's visual player picker */
  thumbnail?:  string;
}

interface FormPlayerProps {
  schema:         FormSchema;
  initialValues?: Record<string, any>;
  mode?:          FormMode;
  onSubmit?:      (values: Record<string, any>) => Promise<void>;
  onCancel?:      () => void;
}

registerFormPlayer()

import { registerFormPlayer } from '@atlas-forms/player-registry';
import { CardSectionPlayer } from './players/CardSectionPlayer';

registerFormPlayer({
  id:          'card-section',
  label:       'Card Section Player',
  description: 'Renders each form section inside its own card panel. Best for admin consoles and multi-section data entry.',
  component:   CardSectionPlayer,
  thumbnail:   '/assets/players/card-section-thumb.png',
});

Registration Timing

Call registerFormPlayer() once, early in your application bootstrap — before any form renders. The registry is a singleton; subsequent calls with the same id overwrite the previous entry and log a warning.

// src/index.tsx  — application entry point

import React from 'react';
import { createRoot } from 'react-dom/client';
import { App } from './App';

// Register all custom players before mounting
import './players/registerPlayers';   // side-effect import

const root = createRoot(document.getElementById('root')!);
root.render(<App />);

// ─── src/players/registerPlayers.ts ─────────────────────────────────────────
import { registerFormPlayer } from '@atlas-forms/player-registry';
import { CardSectionPlayer }  from './CardSectionPlayer';
import { MobilePlayer }       from './MobilePlayer';
import { WizardPlayer }       from './WizardPlayer';

registerFormPlayer({
  id:        'card-section',
  label:     'Card Section',
  component: CardSectionPlayer,
});

registerFormPlayer({
  id:        'mobile',
  label:     'Mobile',
  component: MobilePlayer,
});

registerFormPlayer({
  id:        'wizard',
  label:     'Step Wizard',
  component: WizardPlayer,
});

Reading the Registry

import { getFormPlayer, listFormPlayers } from '@atlas-forms/player-registry';

// Retrieve a single entry by ID
const entry = getFormPlayer('card-section');
// Returns: PlayerRegistryEntry | undefined

// List all registered players (e.g. to populate a UI dropdown)
const allPlayers = listFormPlayers();
// Returns: PlayerRegistryEntry[]

// Example: build a select element from all registered players
const options = listFormPlayers().map(p => ({
  value: p.id,
  label: p.label,
}));

How FormRenderer Resolves the Player

When FormRenderer receives a schema that contains metadata.playerOverride, it looks up that ID in the registry and mounts the registered component instead of the default layout:

// Simplified FormRenderer resolution logic
import { getFormPlayer } from '@atlas-forms/player-registry';

function resolvePlayer(schema: FormSchema): React.ComponentType<FormPlayerProps> {
  const overrideId = schema.metadata?.playerOverride;
  if (overrideId) {
    const entry = getFormPlayer(overrideId);
    if (entry) return entry.component;
    console.warn(`[AtlasForms] Player "${overrideId}" is not registered. Falling back to default.`);
  }
  return DefaultFormLayout;  // built-in player
}
Registration Is Required Before Schema Loading If a form schema references a playerOverride ID that has not been registered yet, FormRenderer will fall back to the default player and log a warning. Ensure all custom player registrations run before any form schema is loaded or rendered.

Player IDs — Naming Convention

ScopeConventionExample
Built-in playersSingle word, lowercasedefault, mobile, wizard
Product-specificproduct-namecrm-detail, hr-onboarding
Tenant-specifictenant-nameacme-branded, gov-accessible
Experimentalexp-name prefixexp-canvas

Unregistering a Player

import { unregisterFormPlayer } from '@atlas-forms/player-registry';

// Remove a player — useful in test teardown or hot-reload scenarios
unregisterFormPlayer('card-section');
Studio Integration Registered players appear in the Player dropdown in Atlas Forms Studio's Form Settings panel. The label string is what users see; the id is written into metadata.playerOverride when the user selects it. If you provide a thumbnail, Studio will show it in the visual card picker.