Adding a tab to a screen sounds like the easiest customization request a client can make, and it usually is, right up until the tab needs a grid bound to a child DAC that does not have an obvious parent-child relationship yet, or the client wants a field on an existing tab conditionally hidden based on a value three fields away. Tab and grid customization is where a lot of Acumatica developers get their first real lesson in the gap between "drag a control onto the screen" and "actually understand what's binding it."
A tab is a layout container, the binding comes from the view
In the Screen Editor, adding a tab is purely a layout operation, it creates a container in the UI tree. What makes that tab show data is binding a grid or a form inside it to a data view exposed by the graph, and that view has to already exist (or you add it via a graph extension) before the tab means anything. New developers sometimes spend time perfecting a tab's visual placement before confirming the underlying data view returns what they expect, which is backwards, get the view working and confirmed via a temporary test screen or the graph's own logic first, then worry about layout.
// Graph extension exposing the child view a new tab's grid will bind to.
public class SOOrderEntry_Extension : PXGraphExtension<SOOrderEntry>
{
public PXSelect<SOOrderApprovalLog,
Where<SOOrderApprovalLog.orderNbr, Equal<Current<SOOrder.orderNbr>>>> ApprovalHistory;
}
Once that view exists and is confirmed to return rows for a test order, the Screen Editor step, adding a tab, dropping a grid, pointing its DataMember at ApprovalHistory, is genuinely the easy part.
Grid columns inherit DAC attributes; overriding them per screen has limits
A grid column's default behavior, its label, its editability, its formatting, comes from the bound DAC field's attributes (PXUIField, PXDBDecimal, and friends). The Screen Editor lets you override some of this per-screen, a different display name, a different width, but not all of it, validation and precision genuinely live on the DAC and cannot be relaxed at the screen layer. I see this confusion most with read-only fields: marking a grid column editable in the Screen Editor does nothing if the underlying field's attribute or a RowSelected handler is setting it non-editable in code, because code-level field state set through PXUIFieldAttribute.SetEnabled takes precedence over the static screen definition.
If a RowSelected handler enables or disables a field conditionally, and a Screen Editor customization also sets that field's editable state statically, whichever runs later wins, and it is not always obvious which that is without checking. I have debugged more than one "the field won't unlock no matter what I change in the layout" ticket that turned out to be a RowSelected handler unconditionally disabling the field on every paint, with the Screen Editor change never standing a chance.
Conditional field and tab visibility belongs in code, not just layout
Hiding a whole tab based on a document status, or a field based on a checkbox elsewhere on the form, is a common ask that the Screen Editor alone cannot fully satisfy, static layout has no concept of "if." That logic belongs in a RowSelected handler using PXUIFieldAttribute.SetVisible for fields, or, for a whole tab, setting the visibility of the tab's underlying container control by its name:
protected virtual void _(Events.RowSelected<SOOrder> e)
{
if (e.Row == null) return;
bool showApprovalTab = e.Row.OrderTotal > 1_000_000m;
PXUIFieldAttribute.SetVisible<SOOrderApprovalLog.approvalNote>(
cache: Base.ApprovalHistory.Cache, row: null, visible: showApprovalTab);
}
For full tab visibility, the equivalent is usually done through the graph's Base.Caches combined with a Screen Editor-declared container ID and a small amount of client-side visibility scripting where the platform's server-side attribute mechanism doesn't reach far enough, worth confirming against the current UI framework version you're targeting since Modern UI and classic screens differ in exactly how tab-level visibility is exposed.
A grid tab you never open still has a cost if it's misconfigured
A data view bound to a grid on a tab the user has not clicked into yet does not execute its query until the tab is activated, that lazy-load behavior is the default and it is worth confirming rather than assuming, especially on cloned or heavily customized screens where a well-meaning previous developer may have forced eager loading to "fix" an unrelated bug. If a screen with several data-heavy tabs feels slow on initial load despite users rarely opening most of the tabs, check whether something is defeating that lazy activation, forcing every tab's view to execute on load is a surprisingly common and avoidable performance regression.
Wrapping up
Tab and grid customization is easy at the layout level and genuinely subtle underneath it: confirm the data view works before worrying about placement, remember that DAC attributes and code-driven field state can override anything set statically in the Screen Editor, and put real conditional visibility logic in RowSelected rather than expecting the static layout to express an "if." Most of the confusing tickets in this category resolve to one of those three things once you know to look for them.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.