Hey everyone,
I’m running into a pretty serious issue with a complex input schema, and I’m wondering if anyone has dealt with something similar or has ideas for workarounds.
Whenever I open an item in the editor that contains deeply nested list structures (list → list → list → object → list, etc.), the entire Builder editor freezes and becomes unresponsive.
This only happens when those lists include many subFields. Here’s a simplified overview of the problematic nesting:
items(list)
→sectionList(list)
→bulletPointSectionList(list)
→bulletPointList(list)
→ multiple objects, images, strings, CTAs, etc.
Editor behavior:
As soon as I expand an item inside sectionList(second level nesting), the UI freezes completely. If I remove some of the subFields, the editor works better: it still freezes but just for a few seconds, then it works again and the section opens.
My questions:
-
Has anyone encountered this issue with deeply nested list schemas?
-
Are there known limitations with the Builder editor handling this level of nesting?
-
Any best practices or patterns to model this safely?
-
Flattening the structure?
-
Changing some lists to
objectinstead oflist? -
Lazy-loading subFields?
-
Structuring it in a different way?
-
I haven’t found a workaround yet, so any ideas would be super helpful.
Thanks! ![]()
Builder content link
Screenshots or video link
Code stack you are integrating Builder with
Angular v20
Reproducible code example
const inputs = [
{
name: 'column',
friendlyName: 'Column',
type: 'string',
required: true,
localized: false,
defaultValue: COLUMN.BOTH,
enum: COLUMN_VALUES,
},
{
name: 'theme',
friendlyName: 'Theme',
type: 'string',
required: true,
localized: false,
defaultValue: THEMES.LIGHT,
enum: THEMES_VALUES,
},
{
name: 'items',
friendlyName: 'Items',
type: 'list',
required: true,
subFields: [
getBuilderImageInput('labelLogo', 'Label Logo', false, true),
getBuilderImageInput('labelIcon', 'Label Icon', false, true),
{
name: 'labelText',
friendlyName: 'Label Text',
type: 'string',
required: true,
localized: true,
},
{
name: 'sectionList',
friendlyName: 'Section List',
type: 'list',
required: true,
onChange: (options: BuilderOnChangeOptions<'sectionList', unknown[]>) => {
const maxItems = 5;
if (options.get('sectionList').length > maxItems) {
options.set('sectionList', options.get('sectionList').slice(0, maxItems));
alert(`You can only have up to ${maxItems} section lists`);
}
},
subFields: [
getBuilderImageInput('sectionLogo', 'Section Logo', false, true),
getBuilderImageInput('preTextImage', 'Pre Text Image', false, true),
{
name: 'headline',
friendlyName: 'Headline',
type: 'string',
required: false,
localized: true,
},
{
name: 'subline',
friendlyName: 'Subline',
type: 'string',
required: false,
localized: true,
},
{
name: 'text',
friendlyName: 'Text',
type: 'string',
required: false,
localized: true,
},
{
name: 'bulletPointSectionList',
friendlyName: 'Bulletpoint Section List',
type: 'list',
required: true,
onChange: (options: BuilderOnChangeOptions<'bulletPointSectionList', unknown[]>) => {
const maxItems = 5;
if (options.get('bulletPointSectionList').length > maxItems) {
options.set(
'bulletPointSectionList',
options.get('bulletPointSectionList').slice(0, maxItems),
);
alert(`You can only have up to ${maxItems} bulletpoint section lists`);
}
},
subFields: [
{
name: 'bulletPointTheme',
friendlyName: 'Bullet Point Theme',
type: 'string',
required: true,
localized: false,
defaultValue: THEMES.LIGHT,
enum: THEMES_VALUES,
},
getBuilderImageInput('bulletPointIcon', 'Bulletpoint Icon', false, true),
{
name: 'bulletPointList',
friendlyName: 'Bulletpoint List',
type: 'list',
required: true,
onChange: (options: BuilderOnChangeOptions<'bulletPointIcon', unknown[]>) => {
const maxItems = 5;
if (options.get('bulletPointIcon').length > maxItems) {
options.set(
'bulletPointIcon',
options.get('bulletPointIcon').slice(0, maxItems),
);
alert(`You can only have up to ${maxItems} bulletpoint icons`);
}
},
subFields: [
{
name: 'bulletPointText',
friendlyName: 'Bulletpoint Text',
type: 'string',
required: false,
localized: true,
},
],
},
],
},
getBuilderImageInput('pastTextImage', 'Past Text Image', false, true),
{
name: 'noButtonCta',
friendlyName: 'No Button CTA',
type: 'object',
required: false,
subFields: [
{
name: 'text',
friendlyName: 'Text',
type: 'string',
required: false,
localized: true,
},
{
name: 'link',
friendlyName: 'Link',
type: 'url',
required: false,
localized: true,
},
],
},
{
name: 'primaryCta',
friendlyName: 'Primary CTA',
type: 'object',
required: false,
subFields: [
getBuilderImageInput('iconBeforeText', 'Icon Before Text', false, true),
{
name: 'text',
friendlyName: 'Text',
type: 'string',
required: false,
localized: true,
},
{
name: 'link',
friendlyName: 'Link',
type: 'url',
required: false,
localized: true,
},
getBuilderImageInput('iconAfterText', 'Icon After Text', false, true),
],
},
{
name: 'secondaryCta',
type: 'object',
required: false,
subFields: [
getBuilderImageInput('iconBeforeText', 'Icon Before Text', false, true),
{
name: 'text',
friendlyName: 'Text',
type: 'string',
required: false,
localized: true,
},
{
name: 'link',
friendlyName: 'Link',
type: 'url',
required: false,
localized: true,
},
getBuilderImageInput('iconAfterText', 'Icon After Text', false, true),
],
},
{
name: 'disclaimer',
friendlyName: 'Disclaimer',
type: 'string',
required: false,
localized: true,
},
],
},
],
},
]
