Designing SharePoint List Forms with JSON Sections, Static Read-Only Fields, and Conditional Visibility
When a SharePoint list form starts growing, the first pain point is usually readability. A flat form with dozens of fields quickly becomes hard to scan, hard to maintain, and hard for end users to trust. The native SharePoint form JSON model helps a lot here because it lets you group columns into sections, reorder them, and mark some fields as read-only. At the same time, it has clear limits: the body configuration is strong for structure, but weak for visual styling and dynamic read-only rules. Microsoft’s form configuration model supports sections and static fieldsettings.readonly, while conditional logic in forms is documented primarily for show/hide behavior, not conditional read-only behavior. (Microsoft Learn)
In this article, I will use fully anonymized names such as Requester, Project Title, Reference Number, Approval Flag, and Objective Summary so the pattern can be reused in any tenant, blog post, or training material without exposing real client field names. This is the safest way to document production-style SharePoint customization. The examples below are based on Microsoft’s documented SharePoint declarative customization model and formatting syntax. (Microsoft Learn)
Why this pattern matters
A practical SharePoint form usually needs three things at the same time:
- a cleaner layout for business users,
- some columns that should always be locked,
- some columns that should only appear in certain situations.
The native SharePoint JSON form model can address all three, but each one is handled differently. Sections organize the form body, fieldsettings can make fields statically read-only, and conditional formulas can show or hide fields depending on another value or the current user. These are separate capabilities, and understanding that separation is the key to designing a maintainable solution. (Microsoft Learn)
What the native form JSON can do well
The SharePoint list form configuration model supports a sections array in the body. Each section can have a displayname and a list of fields. Microsoft also documents fieldsettings, which can be used to make named fields read-only. When body sections are configured, SharePoint switches from a simple one-column form to a multi-column layout. (Microsoft Learn)
That means native form JSON is a good fit for:
- grouping related inputs,
- improving navigation through long forms,
- keeping generated or system fields locked,
- producing a cleaner authoring experience without Power Apps. (Microsoft Learn)
What the native form JSON does not do well
The same model is limited when people try to push it into full UI design territory. The body section model does not provide per-section background styling, per-section borders, or arbitrary layout containers like the richer JSON available in column, row, or header/footer formatting. It also does not document conditional expressions for readonly; static readonly: true is supported, but conditional read-only based on another column is not part of the documented model. (Microsoft Learn)
That distinction matters a lot:
- Body JSON is for structure.
- Header/Footer JSON is more visual.
- Conditional formulas are for visibility logic.
- Power Apps or SPFx are better when you need deep UI control. (Microsoft Learn)
An anonymized body configuration example
Below is a clean, blog-safe example that groups fields into logical blocks. This is the kind of pattern I recommend when documenting SharePoint solutions publicly.
{ "sections": [ { "displayname": "Project Overview", "fields": [ "Requester", "Project Title", "Reference Number", "Approval Flag" ] }, { "displayname": "1 - Business Context", "fields": [ "Primary Request Purpose", "Objective Summary", "Comparison Data Available" ] }, { "displayname": "2 - Expected Results", "fields": [ "Expected Deliverable" ] }, { "displayname": "3 - Source Information", "fields": [ "Data Provider", "Data Delivery Method", "Available Supporting Documents" ] }, { "displayname": "4 - Conditions", "fields": [ "Operating Conditions" ] }, { "displayname": "5 - Timeline", "fields": [ "Required By Date", "Delivery Format" ] }, { "displayname": "6 - Notes", "fields": [ "Additional Notes" ] } ]}
This kind of structure is fully aligned with the documented form-body section model: section names for readability and field grouping for logical organization. (Microsoft Learn)
Adding static read-only fields
Now let us add a second layer: fields that should always be locked in the form. This is where fieldsettings comes in. Microsoft documents readonly as a supported property for form field settings. (Microsoft Learn)
A good real-world use case is locking fields like:
- Requester,
- Reference Number,
- system-generated status values.
Here is the anonymized example:
{ "sections": [ { "displayname": "Project Overview", "fields": [ "Requester", "Project Title", "Reference Number", "Approval Flag" ] }, { "displayname": "1 - Business Context", "fields": [ "Primary Request Purpose", "Objective Summary", "Comparison Data Available" ] } ], "fieldsettings": [ { "name": "Requester", "readonly": true }, { "name": "ReferenceNumber", "readonly": true } ]}
In practice, name should use the internal field name, not the friendly display label. That is an important implementation detail when you move from a blog example into a real tenant. Microsoft’s form configuration documentation describes field settings by field name, and real SharePoint implementations rely on internal names for consistency. (Microsoft Learn)
The big limitation: conditional read-only is not documented
This is where many SharePoint implementations hit a wall. A very common business request is:
- “Make these fields read-only after the item is submitted.”
- “Make these fields read-only for everyone except one coordinator.”
- “Make the field editable only while status is Draft.”
The native form model does not document a conditional expression syntax for readonly. It documents static readonly, but not readonly formulas like =if([$ApprovalFlag] == true, true, false). So while the idea is natural, it is not part of the documented native capability. (Microsoft Learn)
That means this kind of pattern should be avoided in production documentation because it suggests support that is not officially documented:
{ "fieldsettings": [ { "name": "ProjectTitle", "readonly": "=if([$ApprovalFlag] == true, true, false)" } ]}
For blog readers, this is an important architectural lesson: do not confuse native static read-only with dynamic business-state locking. (Microsoft Learn)
The supported workaround: conditional visibility
The supported workaround is to use conditional show/hide formulas in the form experience. SharePoint’s formatting syntax supports Excel-style expressions, references to fields like [$ColumnName], and special tokens like @me for the current user. Microsoft’s syntax reference documents these expression patterns, and the form experience supports conditional visibility formulas. (Microsoft Learn)
This means you can do something very useful even if you cannot do true conditional read-only.
Example: hide a field after approval
=if([$ApprovalFlag] == true, 'false', 'true')
This formula means:
- if the approval flag is true, hide the field,
- otherwise, show it. (Microsoft Learn)
It is not the same as read-only, but from a process perspective it often solves the same business problem: users stop editing the field once the item is considered submitted or approved. (Microsoft Learn)
User-based visibility with @me
Another strong pattern is showing a field only to a specific person, reviewer, or coordinator. SharePoint formatting syntax supports @me, which lets expressions compare the current user to another value. Microsoft documents @me as part of the formatting expression language. (Microsoft Learn)
For example, to show an editable field only to a single designated user:
=if(@me == 'reviewer@contoso.com', 'true', 'false')
And to combine user logic with process-state logic:
=if(@me == 'reviewer@contoso.com' && [$ApprovalFlag] != true, 'true', 'false')
This is one of the most useful native patterns in SharePoint forms because it gets very close to “editable only for one person until submission,” even though it is technically implemented as conditional visibility, not conditional read-only. (Microsoft Learn)
Why anonymization improves technical documentation
Using anonymized field names is not only about privacy. It also makes your documentation more reusable. A reader can understand the pattern immediately:
- Requester instead of a real employee field,
- Project Title instead of a client-specific business term,
- Approval Flag instead of a tenant-specific boolean,
- Reference Number instead of a proprietary identifier.
This produces a cleaner learning artifact and keeps the article focused on architecture rather than tenant-specific details. It is especially useful for SharePoint blog posts because the real educational value is in the pattern, not the original column labels. This is an implementation best practice and a documentation best practice, even though it is not a Microsoft feature itself. The underlying SharePoint capabilities still come from the documented form configuration and syntax model. (Microsoft Learn)
Recommended design pattern for production teams
For most teams, the best native design pattern looks like this:
- use body
sectionsto make the form readable, - use
fieldsettings.readonlyonly for fields that are always locked, - use conditional formulas for show/hide behavior,
- use
@mefor reviewer-specific visibility, - move to Power Apps or SPFx only when you truly need richer interaction or styling. (Microsoft Learn)
This gives you a practical balance between simplicity, maintainability, and user experience. It also keeps the solution inside the native SharePoint model for as long as possible. (Microsoft Learn)
A complete anonymized example for a blog
Below is a realistic, publishable example that shows the structure and the static lock pattern together.
{ "sections": [ { "displayname": "Project Overview", "fields": [ "Requester", "Project Title", "Reference Number", "Approval Flag" ] }, { "displayname": "1 - Business Context", "fields": [ "Primary Request Purpose", "Objective Summary", "Comparison Data Available" ] }, { "displayname": "2 - Expected Results", "fields": [ "Expected Deliverable" ] }, { "displayname": "3 - Source Information", "fields": [ "Data Provider", "Data Delivery Method", "Available Supporting Documents" ] }, { "displayname": "4 - Conditions", "fields": [ "Operating Conditions" ] }, { "displayname": "5 - Timeline", "fields": [ "Required By Date", "Delivery Format" ] }, { "displayname": "6 - Notes", "fields": [ "Additional Notes" ] } ], "fieldsettings": [ { "name": "Requester", "readonly": true }, { "name": "ReferenceNumber", "readonly": true } ]}
And then, outside this JSON, you can configure field-level conditional visibility such as:
=if([$ApprovalFlag] == true, 'false', 'true')
or:
=if(@me == 'reviewer@contoso.com' && [$ApprovalFlag] != true, 'true', 'false')
The separation is important: read-only is configured in form JSON, while conditional visibility is configured through form conditional formulas using SharePoint expressions. (Microsoft Learn)
Final thoughts
This style of SharePoint form customization is not flashy, but it is extremely effective. It respects the platform instead of fighting it. Native JSON body formatting gives you a clean way to transform a long, chaotic form into a structured experience. Static read-only settings help protect system-owned fields. Conditional visibility formulas add process awareness and user awareness. Once you understand the line between those three capabilities, your SharePoint forms become far easier to design and document. (Microsoft Learn)
The most important takeaway is simple: use native JSON for structure, use conditional formulas for visibility, and do not expect native conditional read-only behavior unless you move to a richer customization model. (Microsoft Learn)
Step-by-step implementation table
| Step | Goal | Native feature | Example |
|---|---|---|---|
| 1 | Organize the form into logical blocks | sections | Project Overview, Business Context, Timeline |
| 2 | Keep system-owned fields locked | fieldsettings.readonly | Requester, ReferenceNumber |
| 3 | Prevent editing after submission | Conditional visibility | =if([$ApprovalFlag] == true, 'false', 'true') |
| 4 | Show fields only to a specific reviewer | @me expression | =if(@me == 'reviewer@contoso.com', 'true', 'false') |
| 5 | Combine process state and user logic | @me + field comparison | =if(@me == 'reviewer@contoso.com' && [$ApprovalFlag] != true, 'true', 'false') |
| 6 | Keep blog documentation reusable | Anonymization | Replace real field names with neutral placeholders |
Technical summary table
| Capability | Supported natively | Notes |
|---|---|---|
| Group fields into body sections | Yes | Documented in SharePoint form configuration. (Microsoft Learn) |
| Static read-only fields | Yes | Supported through fieldsettings.readonly. (Microsoft Learn) |
| Conditional read-only | No documented native support | Use conditional visibility instead. (Microsoft Learn) |
| Conditional show/hide formulas | Yes | Uses SharePoint expression syntax. (Microsoft Learn) |
Current-user logic with @me | Yes | Supported by formatting syntax. (Microsoft Learn) |
| Per-section body background styling | Not part of the documented body-section model | Better handled in header/footer or richer customizations. (Microsoft Learn) |
| Full UI control | Not with native form body JSON | Power Apps or SPFx is the next step. (Microsoft Learn) |
