OptionalchromePin this contribution to a chrome bucket instead of its own rail item.
'details' — leftover own-fields group. 'more' — overflow folder.
OptionalcontributionIdentity for last-wins collapse. Two registrations with the same key
compete; highest ClassFactory Priority wins. Omit to derive:
related:${relatedEntity}:${relatedJoinField} when claiming a
relationship, otherwise the registration is unique and never collapses.
OptionalcountWhat to count for this contribution. Omit to derive it from
relatedEntity / relatedJoinField. false disables the
prefetch. A contribution with no count source can still report its own
count after it mounts via FormComponent.SetSectionRowCount(key, n).
OptionalinclusionL1 inclusion for this contribution (same verbs as relationships).
'Primary' — own first-class rail item, in the lead band before Details.
'More' — overflow folder. 'None' — hidden.
L3 MJ: Form Chrome Rules still wins. chromeGroup still merges.
OptionalinA section this contribution draws inside, replacing nothing.
OptionalleadsOpen a NEW (unsaved) record on this contribution instead of the first first-class group.
A saved record opens where the user last was, or on the lead group. That is right for reading a record and wrong for creating one: the lead group is usually a summary, and a summary of a record with no data is a page of blanks the user has to look past to find where typing starts.
Only consulted when the record is unsaved, so it cannot change how an existing record opens.
If several contributions on one entity set it, the highest ClassFactory Priority wins, matching
how every other conflict between registrations is settled.
Optionalpresentation'bare' = a hero strip that draws no collapsible chrome and is never a rail item.
'panel' (default) = a normal collapsible section.
This is how a compiled panel declares hero-ness, and it is the same field a
MJ: Entity Form Contributions row carries, so the container treats both sources
identically instead of guessing from a contribution key.
OptionalrelatedWhen set, this panel replaces the default related-entity grid for
that relationship on entity's form. The baked CodeGen panel (if any)
is hidden; the stock fill-in grid is not mounted.
OptionalrelatedDisambiguates two FKs to the same related entity (BillTo vs ShipTo).
Compared after stripping wrapping [].
OptionalreplacesFields this contribution stands in for, all within one section. The panel renders at
the top of that section and the named fields are not drawn. Use instead of
replacesSectionKey when the panel replaces some inputs rather than a whole group.
OptionalreplacesCodeGen SectionKey of a baked field (or other) panel this contribution
replaces — e.g. 'details', 'personalIdentity'. Hidden at runtime via
HiddenSectionKeys. Use with slot: 'before-fields' for a form hero that
is not a collapsible panel. Must name a concrete entity (not '*').
OptionalreplacesSections this contribution stands in for, all within one tab. It draws in the place of the first of them in the form's order, and the others are not drawn.
OptionalsectionThe SectionKey of the <mj-collapsible-panel> this contribution renders,
when it differs from contributionKey (e.g. contributionKey: 'links'
rendering SectionKey="activityParticipants"). Counts, badges and whenEmpty
are keyed by the section the user sees. Omit when they are the same.
OptionalsectionWhere inside its section it draws, for inSectionKey and field claims. Absent means the start.
OptionalshowPrefetch this contribution's row count when the record loads and show it as
a badge. Omit to inherit the parent entity's UI.Form.ShowRelatedCounts
(default true).
OptionalsortOptionalwhenWhat the form does with this contribution's section when it has 0 rows.
'show' (default) | 'hide' | 'more' (moved into the More folder while
empty). Same verbs as EntityRelationship.Configuration.UI.whenEmpty; omit to
inherit the parent entity's UI.Form.RelatedWhenEmpty.
Shape of the
metadataobject every BaseFormPanel registration MUST attach via@RegisterClass(BaseFormPanel, { metadata: {...} }). The<mj-form-panel-slot>host filters registrations by matching against this shape — registrations without it are silently ignored.entity— the exact entity name (case-sensitive equality enforced by the slot host), OR the wildcard'*'to register an entity-agnostic panel that mounts on EVERY entity's form. Wildcard panels are expected to self-hide (render nothing) when they don't apply to the current record, so the cross-cutting registration stays unobtrusive on forms it has no business on.slot— which slot the panel renders into.sortKey— higher = earlier within the slot. Defaults to 0 if omitted. Use ranges (e.g., 100/50/10) so future panels can wedge in without recomputing every neighbor's sort.