Builder editor freezes when opening deeply nested list inputs

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 object instead of list?

    • Lazy-loading subFields?

    • Structuring it in a different way?

I haven’t found a workaround yet, so any ideas would be super helpful.

Thanks! :folded_hands:

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,
                    },
                ],
            },
        ],
    },
]