API reference
import { DeclarativeForm } from 'declarative-forms';new DeclarativeForm(options)
interface DeclarativeFormOptions {
fields: readonly FieldDescriptor[];
buttons?: ButtonMap;
confirmLabel?: string;
onConfirm?: (values: FormValues) => unknown;
onCancel?: () => void;
classNames?: readonly string[];
persistFile?: (file: File) => Promise<URL | string>;
tooltipProvider?: TooltipProvider;
}| Option | Notes |
|---|---|
fields | Required. See Field kinds |
buttons | Keyed by visible label. Replaces the default OK button |
confirmLabel | Renames the default button. Ignored when buttons is given |
onConfirm | Run on confirm. May be async |
onCancel | Presence enables dismissal — ✕ button and Escape |
classNames | Added to the inner <form> element |
persistFile | Required by file fields |
tooltipProvider | Swap the tooltip implementation |
Constructing does not display anything. Call openInModal() or appendInElement().
Values
getValues(): FormValues
Current values keyed by field name. Fields hidden by isActive are omitted; message fields never appear; activeTab is always present.
subscribeOnInput(subscriber): () => void
Called whenever values change. Returns an unsubscribe function.
const off = form.subscribeOnInput((values) => console.log(values));
off();field(name): FieldHandle | undefined
interface FieldHandle {
readonly name: string;
readonly element: HTMLElement; // the control
readonly wrapper: HTMLElement; // .dl-form-field-wrapper
getValue(): unknown;
setValue(value: unknown): void;
focus(): void;
setLoading(loading: boolean): void;
}Replaces v1's descriptor.domElement. Returns undefined for an unknown name.
fields: readonly FieldHandle[]
Every field handle, in declaration order.
Lifecycle
whenReady(): Promise<void>
Resolves once initial options have loaded and defaults have been applied.
update(source?, force?, includeTab?): Promise<void>
Manually run the update cycle. Rarely needed — prefer ctx.requestUpdate() from inside a field.
updateComputedFields(): Promise<void>
Re-run every computed field. Button actions do this automatically.
Display
openInModal(options?): HTMLElement
interface OpenInModalOptions {
classNames?: readonly string[]; // added to inner .modal
wrapperClassNames?: readonly string[]; // added to outer .dl-modal
}Returns the outer div.dl-modal element — not a controller object. See Modals.
appendInElement(host, options?): HTMLElement
Render inline. options.classNames are added to the wrapper.
modalElement: HTMLElement | undefined
The outer element once displayed.
hide() / show()
Toggle the dl-modal-hidden class without closing.
getHTML(): string
The form's outer HTML. Intended for tests and snapshots.
dom / formElement
The .dl-form wrapper, and the <form> the fields live in.
Closing
| Method | onConfirm | onCancel | Removes |
|---|---|---|---|
close(action?) | yes, or action | no | yes, unless embedded |
cancel() | no | yes | yes |
remove() | no | no | yes |
destroy() | no | no | yes, plus releases resources |
close() returns a promise that resolves after your callback settles. cancel() is a no-op when the form has no onCancel.
Tabs
setActiveTab(tab?)
Switch tabs. With no argument, re-applies the current tab as a resync. Selecting a tab that is not rendered is a no-op.
refreshTabs()
Re-apply tab visibility to fields. Called by the modal stack when a dialog is revealed.
Tooltips
form.setTooltip(name, text, icon?, className?);
form.setTooltipSuccess(name, text);
form.setTooltipWarning(name, text);
form.setTooltipError(name, text);
form.setTooltipLoading(name, text);
form.resetTooltip(name);
form.resetTooltips(['a', 'b']);All are silent no-ops for a field that declares no tooltip. resetTooltip restores the original text and the ? icon.
Scoped to the form, so two forms with a same-named field do not collide.
Buttons
interface ButtonDescriptor {
action?: (values: FormValues) => unknown;
id?: string;
class?: string;
isActive?: (ctx: ButtonContext) => boolean | Promise<boolean>;
isVisible?: (ctx: ButtonContext) => boolean | Promise<boolean>;
doNotCloseModal?: boolean;
}
interface ButtonContext {
data: FormValues;
parentData: FormValues | undefined;
stackData: readonly FormValues[];
}isActive / isVisible require an id. See Buttons.
Tooltip provider
interface TooltipProvider {
attach(element: HTMLElement, content: string): void;
detach(element: HTMLElement): void;
}Default is NativeTooltipProvider (zero dependencies, shows on hover and focus). Supply your own to use tippy.js or another library:
new DeclarativeForm({ fields, tooltipProvider: myProvider });Other exports
| Export | Purpose |
|---|---|
html, escapeHtml, SafeHtml, isSafeHtml | Text & HTML safety |
Field, FieldRegistry, defaultFieldRegistry | Custom field kinds |
DlSelect, DlOption, defineDlSelect | <dl-select> |
injectStyles, DL_SELECT_STYLES | Manual combobox style injection |
ModalStack, globalModalStack | Isolated modal stacks (useful in tests) |
ModalView, TabBar, ButtonBar, TooltipController | UI internals |
FormModel, UpdateScheduler, IdGenerator | Core internals |
deepEqual | The structural comparison used for change detection |
All descriptor and option types are exported as types.