Action Libraries Overview
Form Action Libraries let you package reusable action handlers as distributable npm packages. Instead of wiring the same business logic into every form individually, you write it once, register it as a library, and reference it by type string in any form schema across the ecosystem.
What Is an Action Library?
An action library is an npm package that:
- Exports one or more action handler functions
- Registers each handler with a unique type key using
registerFormAction() - Has
@atlas-forms/types-jsas a peer dependency (not a regular dependency) - Can be published to npm or distributed through InstallHub/MarketHub
Once installed and registered, any form schema in any tenant can reference the library's action types in its actions[] array — no additional code required.
Why Build Action Libraries?
Code Reuse
Write the "Approve via Docusign" handler once. Use it in 50 different forms without copying code.
Team Distribution
A shared library installed by your team provides consistent behavior across all forms in a product area.
Marketplace Publishing
Publish to MarketHub for other tenants to install. Action libraries are first-class InstallHub packages.
Versioning
Semantic versioning on npm. Fix a bug in the library and all forms using it get the fix on next install.
Library vs Inline Custom Action
| Aspect | Inline Custom (Guide 2) | Action Library (this guide) |
|---|---|---|
| Handler location | In your app's codebase | Separate npm package |
| Reusability | Single application | Any application that installs the package |
| Distribution | Via your app deployment | npm / InstallHub / MarketHub |
| Versioning | Your app version | Independent semver |
| Best for | One-off or app-specific logic | Shared business actions across teams |
The Registration Pattern
Every action library follows the same three-step registration pattern:
Implement the handler
Write a function with signature (context: FormActionContext) => Promise<void>.
Register with a type key
Call registerFormAction('my-type', handler) during app initialisation.
Reference in form schema
Use "type": "custom", "config": { "handlerType": "my-type" } in any form.
Minimal Library Example
// src/index.ts — the library's entry point
import { registerFormAction } from '@atlas-forms/control-registry-js';
import type { FormActionContext } from '@atlas-forms/types-js';
const sendSlackNotification = async (ctx: FormActionContext): Promise<void> => {
const { formValues, config } = ctx;
await slackApi.send({
channel: config?.channel ?? '#forms',
text: `Form submitted: ${JSON.stringify(formValues)}`
});
ctx.complete();
};
// Call this once at app startup
export function registerSlackActions(): void {
registerFormAction('slack-notify', sendSlackNotification);
}
// In your app's main.tsx
import { registerSlackActions } from '@myorg/atlas-slack-actions';
registerSlackActions();
FormActionContext interface and the inline custom action pattern.